问题标签 [starvation]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
0 回答
1100 浏览

multithreading - 为什么我的 goroutine 饿死了?

概述

我正在编写一个程序,其中在一个 goroutine 中启动服务器。服务器有几个不同的 goroutine :

  1. 主协程:它处理初始化,启动第二个协程来监听新的连接(2),然后进入一个无限循环来处理从连接(即客户端)接收到的数据。
  2. 监听 goroutine:这个 goroutine 进入一个无限循环,不断地监听新的连接。如果一个新的连接被接受,另一个 goroutine 被启动,它监听来自连接的消息,直到它被关闭。

服务器似乎运行良好。我可以成功添加许多新连接,并且在这些新连接最初被服务器接受后,我还可以在这些新连接上发送数据。

我的客户很简单。还有两个 goroutine:

  1. 主 goroutine:它处理初始化,向服务器注册客户端,启动第二个 goroutine 以从服务器读取数据 (2),然后进入无限循环以对从服务器接收到的数据进行操作。
  2. 第二个 goroutine:这个 goroutine 不断尝试从服务器读取数据,直到连接关闭。

饥饿

我在客户端的 goroutine 饥饿问题上遇到了很大的问题。具体来说,客户端的第二个 goroutine 总是饿死。这是饥饿的 goroutine 的来源:

我确信一条消息正在从服务器发送到客户端。我也确信正在发送的消息以protocol.EndOfMessage. 我也确信我从服务器获取数据的方法是正确的,因为我使用相同的代码来注册客户端,而不是在无限循环中运行它,我允许它预先指定的尝试次数。

由于某种原因,我的客户不会收到数据。

为了确定我没有误解 goroutines 的性质,如果我用以下代码替换上面的代码:

goroutine 完全按预期工作:一切都像以前一样运行,但是“在接收者 goroutine 中!” 不断打印。因此,在这种情况下,例程肯定是正确执行的。

我的处理程序

现在,update(msg, debug)只需调用fmt.Println(msg).

我能做些什么来彻底解决这个问题吗?我觉得放弃优先级/强制调度程序运行是解决这个问题的一个 hacky 解决方案。

0 投票
0 回答
98 浏览

php - PHP 群如何防止饥饿?

我有一个关于 PHP flock() 函数的问题:

PHPflock() 如何防止进程饥饿?

如果有一个进程 R 一直想要读取一个文件,而一个进程 W 想要在读取完成时写入文件(想要一个独占锁)。它如何使进程 W 不饿死?

有没有办法使用flock() 并使进程W 在PHP 中不会饿死?

0 投票
1 回答
854 浏览

java - 链表节点的线程安全切换,而不锁定整个列表

我正在学习线程、锁等。因此,我不想使用synchronized关键字或任何thread-safe其他类semaphoreReentrantLock(没有原子变量)。

我想要一种同步LinkedList<T>Node<T>,按大小排序T(假设它Timplements一个interface具有sizeincrement功能和lockunlock功能)。我希望能够Nodes用它们的T.getSize()功能替换两个而不锁定所有列表。

例如,如果我只有一个线程,该函数将是一个“经典”替换函数,如下所示:

现在让我们来解决同步问题。

我想过尝试做类似的事情来lock为我创建一个Nodes

问题是这并不是线程安全的,并且可能会发生死锁。例如,假设我们现在有Node a, Node b那个a.next == b and b.prev==a,如果线程 A 试图在 a 上使用替换函数,而线程 B 试图在 b 上使用替换函数,它们都将被锁定,我将无处可去。

如何使替换功能thread safe没有lock整个列表?我想避免dead-lockand starvation

谢谢!

0 投票
0 回答
939 浏览

java - 垃圾收集器中的 Heap_lock 饥饿

垃圾收集器线程似乎饿死等待 Heap_lock。这是 GC 线程的堆栈跟踪

我的 Java 应用程序产生了大约 300 个线程。他们也会挨饿。这是一个堆栈跟踪示例:

运行我的应用程序几个小时后,饥饿就开始了。

我尝试了三个收集器:使用默认设置的 UseG1GC、UseParallelGC 和 UseConcMarkSweepGC,但仍然感到饥饿(没有尝试过串行 GC)。

我在 OSX 10.11.5 上使用 Java 1.8.0_92(构建 1.8.0_92-b14,Java HotSpot(TM) 64 位服务器 VM,构建 25.92-b14,混合模式)。

有足够的堆空间Xmx6G;我没有看到完整的 GC。我将 GC 线程 XX:VMThreadStackSize 的堆栈增加到 10MB,但得到了同样的饥饿。我还使用了较旧的 Java,同样饥饿。我没有看到任何致命错误日志 ( http://www.oracle.com/technetwork/java/javase/felog-138657.html )。

请建议如何调试这种饥饿。

2016 年 6 月 19 日更新:

我按堆栈跟踪对挂起的线程进行了分组,您可以看到

挂在 GangWorker::loop()

挂在 ConcurrentG1RefineThread::wait_for_completed_buffers()

编译器线程挂起

此外,其余线程具有这些堆栈跟踪(每个线程一行)

我省略了我的 300 个线程,因为 Java 不在安全点(jstack 不起作用),所以饥饿不能是因为我的(用户)线程。饥饿肯定是由 VM 线程引起的(我在上面列出的所有这些都带有堆栈跟踪)。

2016 年 6 月 24 日更新:

我做了jstack -F,我的线程被阻塞了,一些内存操作,比如这个

但 jstack 不显示垃圾收集器线程。为此,我在同一个进程上运行示例命令,就像在您看到饥饿的 GC 线程之前一样:

当我只用 30 个线程(而不是 300 个)运行我的应用程序时,饥饿就消失了。

我们需要找出垃圾收集器的__psynch_cvwait在哪个锁上等待,但是jstack没有说这个。可能代码检查是最好的选择。

0 投票
1 回答
548 浏览

c++ - 如何让作家线程饿死

我已经使用 C++14 的 shared_timed_mutex 编写了读写器问题的实现。在我看来,下面的代码应该会导致写入器饿死,因为太多的读取器线程一直在数据库上工作(在这个例子中是一个简单的数组):写入器没有机会获得锁。

当线程正在读取、写入、尝试以阻塞模式或通过try_lock()方法获取锁时,我向标准输出添加了一些输出,但为了清楚起见,我删除了输出。我在 main 方法中进一步启动线程。当我运行程序时,编写器总是有机会写入数组(导致所有读取器线程阻塞,这没关系),但正如我上面所说,编写器根本不应该能够访问,因为有太多许多读取器线程从数组中读取。即使我根本不让读取线程进入睡眠状态(参数 0),写入线程也会以某种方式找到获取互斥锁的方法。那我怎么让作家饿死呢?

0 投票
2 回答
2917 浏览

linux - linux进程调度程序如何防止进程饥饿

我读过linux内核包含许多调度类,每个类都有自己的优先级。为了选择一个新的进程来运行,进程调度程序从最高优先级迭代到最低优先级。如果在一个类中找到一个可运行的进程,则选择最高优先级的进程从该类运行。

摘自 Robert Love 的 Linux 内核开发:

进程调度的主要入口点是函数 schedule() ,定义在 kernel/sched.c 中。这是内核的其余部分用来调用进程调度程序的函数,决定运行哪个进程然后运行它。schedule() 对于调度程序类来说是通用的。也就是说,它找到具有可运行进程的最高优先级调度程序类,并询问它接下来要运行什么。鉴于此,schedule() 很简单也就不足为奇了。该函数的唯一重要部分——否则在这里重现太无趣——是它对 pick_next_task() 的调用,也在 kernel/sched.c 中定义。 pick_next_task() 函数遍历每个调度程序类,从最高优先级开始,并选择最高优先级类中的最高优先级进程。

让我们想象以下场景。有一些进程在较低优先级中等待,并且进程不断被添加到较高优先级中。低优先级的进程不会饿死吗?

0 投票
1 回答
106 浏览

ssl - 由于读取或写入期间无限重新协商而导致的 DoS

OpenSSL 和/或 SSL/TLS 协议是否提供某种针对无限重新协商的内置保护?

特别是,是否有可能SSL_read()因为远程端(可能是恶意的)不断请求重新协商而不发送有效负载数据而永远继续执行?

我对此感到担心,因为我想使用轮询机制从单个线程为多个 SSL 连接提供服务,并确保一种公平形式,其中一个连接上的 I/O 处理不会导致 I/O 饥饿其他连接。

当我以非阻塞模式在套接字上调用常规read()时,我知道它不能永远执行下去,因为缓冲区最终会填满。

但是,由于SSL_read()可以透明地处理重新协商,在我看来,如果远程端(可能是恶意的)在不发送有效负载数据的情况下继续请求重新协商,并且底层传输层足够快以使底层读取和写入永远不会失败EWOULDBLOCK,那么SSL_read()可以最终永远执行,从而使其他连接挨饿。

因此我的问题是:OpenSSL 或协议是否有避免这种情况的机制?顺便说一句,这个问题同样适用SSL_write()

编辑:例如,我是否可以确定在进行多次重新谈判之前SSL_read()会返回一个SSL_ERROR_WANT_READ/SSL_ERROR_WANT_WRITE指示,即使底层的读/写操作永远不会失败EWOULDBLOCK

编辑:出于这个问题的目的,假设我使用的是常规套接字 BIO ( BIO_s_socket()),并且底层套接字处于非阻塞模式。

0 投票
2 回答
2550 浏览

java - Spring Scheduler同步方法饥饿

假设我有一个调度程序

不同情况下不同的任务触发器会调用countIt。

当两个或多个job同时调用countIt时,会造成饥饿。

谁能告诉我是否有办法避免这种情况?

0 投票
1 回答
455 浏览

linux - 为什么我的程序中的这个线程会饿死?

我有一个有大约 80 个线程的程序。它在 linux 3.36 上运行在 ~50ish 核心机器上。最多有 2 个这样的程序同时运行,并且它们是相同的。机器上没有其他任何东西在运行。

线程本身是具有 SCHED_RR(循环)策略的实时 linux pthread。

  • 10 是最高优先级(是的,我将 ulimit 设置为 99)并将 cpu 亲和性设置为 10 个核心。换句话说,它们都被固定在自己的核心上。
  • 大约 60 个是中等优先级。
  • 大约 10 个是低优先级。

10 个最高优先级的线程一直在使用 cpu。

其余的在做网络 IO 以及在 CPU 上做一些工作。问题是:我看到一个低优先级线程被饿死,有时一次超过 15 秒。此特定线程正在 TCP 套接字上等待某些数据。我知道数据已完全发送,因为我可以看到连接另一端的服务器已发送数据(即,它在发送数据后记录时间戳)。通常线程需要毫秒来接收和处理它,但偶尔会在其他服务器成功发送数据后需要 15 秒。请注意,增加线程的优先级并将其固定到 CPU 已经消除了这个问题,但这不是一个长期的解决方案。我一开始就没想到这种行为 - 15 秒是很长的时间。

有谁知道为什么会发生这种情况?我们已经排除它是程序/线程中的任何逻辑。另请注意,该程序是用 C 编写的。

0 投票
2 回答
2337 浏览

c++ - 如何防止线程饥饿

我正在编写一个零延迟的云游戏服务器。这是一个软件管道。在第一阶段,我们捕获屏幕,在第二阶段,我们将其编码为视频。

然而,经过一段时间后,第二阶段冻结。我尝试了许多独立于平台的方法,但是它们中的任何一个最终都会冻结。How to prevent threads from starvation in C++11的答案表明我们应该使用互斥锁。我尝试过这个。它可以持续更长时间,但有时仍会冻结(很少)。我认为互斥锁也不是防止线程饥饿的明确提示。(也许我做错了?)

现在我同时使用互斥锁和禁用 Windows 优先级提升功能,但我根本不喜欢这个解决方案。谁能提供一个无饥饿的生产者和消费者的例子(在 C++11 中更好)?

生产商:

消费者:

最初我没有对循环队列做任何保护。我认为没有竞争条件(一个生产者和一个消费者)。然后我尝试添加互斥体但没有任何改变......