C 向进程中的所有线程发送信号
在不保留当前线程列表的情况下,我试图看到一个实时信号被传递到进程中的所有线程。我的想法是这样做:C 向进程中的所有线程发送信号,c,multithreading,pthreads,posix,signals,C,Multithreading,Pthreads,Posix,Signals,在不保留当前线程列表的情况下,我试图看到一个实时信号被传递到进程中的所有线程。我的想法是这样做: 最初安装了信号处理程序,并且在所有线程中解除了信号阻塞 当一个线程想要发送“广播”信号时,它会获取一个互斥锁并设置一个全局标志,表明广播正在进行 发送器为自己阻塞信号(使用pthread\u sigmask),并进入一个循环,反复调用raise(sig),直到sigpending指示信号处于挂起状态(信号被阻塞的线程不存在) 当线程接收到信号时,它们会对其进行操作,但会在信号处理程序中等待广播标志
- 最初安装了信号处理程序,并且在所有线程中解除了信号阻塞
- 当一个线程想要发送“广播”信号时,它会获取一个互斥锁并设置一个全局标志,表明广播正在进行
- 发送器为自己阻塞信号(使用
),并进入一个循环,反复调用pthread\u sigmask
,直到raise(sig)
指示信号处于挂起状态(信号被阻塞的线程不存在)sigpending
- 当线程接收到信号时,它们会对其进行操作,但会在信号处理程序中等待广播标志被清除,以便信号保持屏蔽状态
- 发送方通过解锁信号完成循环(以获得自己的传递)
- 当发送方处理自己的信号时,它会清除全局标志,以便所有其他线程都可以继续其业务
pthread\u sigmask
没有得到尊重。如果我在strace
下运行测试程序,一切正常(可能是由于不同的调度时间),但只要我单独运行它,发送方就会收到它自己的信号(尽管阻止了它……),而其他线程都不会被调度
你知道哪里不对吗?我尝试使用sigqueue
而不是raise
,探测信号掩码,到处添加sleep
,以确保线程耐心地等待信号,等等。现在我不知所措
编辑:多亏了psmears的回答,我想我理解了这个问题。这里有一个潜在的解决方案。反馈会很好:
- 在任何给定的时间,我都可以知道正在运行的线程数,如果需要,我可以在广播信号期间阻止所有线程的创建和退出
- 想要执行广播信号的线程获取锁(因此没有其他线程可以同时执行),然后为自己阻塞信号,并向进程发送
信号,然后为自己解除阻塞信号num_threads
- 信号处理程序以原子方式递增一个计数器,信号处理程序的每个实例等待该计数器等于
返回num_threads
- 执行广播的线程也会等待计数器达到
,然后释放锁num_threads
sigqueue
是否可靠地通知调用者(在这种情况下,我将循环直到成功),或者信号可能会无声地丢失
编辑2:它似乎正在工作。根据sigqueue
的文档,如果无法对信号进行排队,它将返回EAGAIN
。但是为了健壮性,我决定继续调用sigqueue
,直到num_threads-1
信号处理程序运行,在发送num_threads-1
信号后,交错调用sched_yield
在线程创建时有一个争用条件,计算新线程的数量,但我用奇怪的(ab)读写锁解决了这个问题。线程创建是“读取”,而广播信号是“写入”,因此,除非有线程尝试广播,否则它不会在线程创建时创建任何争用。在多线程程序raise(sig)中相当于pthread_kill(pthread_self(),sig)。 Try kill(getpid(),sig)
raise()
将信号发送到当前线程(仅限),以便其他线程不会接收到该信号。我怀疑strace
使事情正常运行的事实是strace
中的一个缺陷(由于它的工作方式,它最终会截获发送到进程的所有信号并重新提升它们,因此它可能以错误的方式重新提升它们……)
您可能可以使用kill(getpid(),)
将信号作为一个整体发送到当前进程
但是,您可能看到的另一个潜在问题是,sigpending()
可以在所有线程都接收到信号之前指示该信号在该进程上处于挂起状态-这意味着该进程至少有一个这样的信号处于挂起状态,并且没有CPU可以运行线程来传递该信号
你能详细描述一下你的目标吗?你希望它有多便携?几乎可以肯定的是,有一种更好的方法可以做到这一点(信号几乎总是一个令人头疼的问题,特别是当与线程混合时…鉴于您显然可以锁定线程的创建和销毁,您是否可以让“广播”线程将所需的更新发布到每个线程队列中的线程本地状态,每个线程在使用线程本地状态时检查哪些线程?如果有未完成的更新,它将首先应用它们。您正在尝试同步一组线程。
从设计模式的角度来看,针对您的问题的pthread本机解决方案将是pthread屏障。我的印象是,除非所有线程都阻止该信号,否则该信号不会显示为挂起。但是我怀疑你的答案是正确的-第一次,循环发送一个信号,然后由于没有其他线程立即被安排处理它,它显示为挂起,发送线程取消阻止它并自行处理它…:-(至于我试图实现的目标——我希望能够在每个线程中运行一段代码(利用线程本地状态),而不必跟踪所有正在运行的线程的列表。这一要求背后的思想是需要在