我写了一个代码,其中有两个线程并行运行。
第一个是启动第二个线程的主线程。 第二个线程只是一个简单的线程执行空while循环。
现在我想暂停/挂起第二线程的执行第一线程谁创build它。 过了一段时间,我想恢复执行第二个线程(通过发出一些命令或函数)从暂停/暂停的地方。
这个问题不是关于如何使用互斥锁,而是如何挂起一个线程。
在Unix规范中有一个叫做pthread_suspend的线程函数,另一个叫pthread_resume_np,但是由于某些原因,制作Linux,FreeBSD,NetBSD等的人还没有实现这些功能。
所以理解它,功能根本就不存在。 有解决方法,但不幸的是,它不同于在Windows上调用SuspendThread。 你必须做各种不可移植的东西,使线程停止并开始使用信号。
停止和恢复线程对于调试器和垃圾收集器是至关重要的。 例如,我已经看到了Wine的一个版本,它无法正确实现“SuspendThread”函数。 因此,使用它的任何Windows程序将无法正常工作。
我认为有可能使用基于JVM使用这种信号技术作为垃圾收集器的信号来正确使用这些信号,但是我也刚刚在网上看到一些人们注意到JVM的死锁等等的文章,有时候不能重放。
所以为了回答这个问题,除非你有一个很好的实现了pthread_suspend_np的Unix,否则你不能正确地挂起和恢复Unix的线程。 否则,你被困在信号。
信号的大问题是当你有大约五个不同的库链接到同一个程序,并试图同时使用相同的信号。 出于这个原因,我相信你不能在一个程序中实际使用ValGrind和Boehm GC之类的东西。 至少在最低级别的用户空间中没有主要的编码。
这个问题的另一个答案可能是。 做一下Linuz Torvalds对NVidia做的事,指责他,让他实现Linux中缺少的两个最关键的部分。 首先是pthread_suspend,其次是内存页上的一个脏位,这样可以实现适当的垃圾收集器。 在网上开始一个大的请愿,并不断翻动那个手指。 也许到Windows 20出来的时候,他们会意识到挂起和恢复线程以及脏位实际上是Windows和Mac比Linux更好的根本原因之一,或者任何没有实现pthread_suspend的Unix,也是一个脏位在虚拟页面上,像VirtualAlloc在Windows中一样。
我不活在希望之中。 实际上对于我来说,我已经花了很多年的时间来计划我的未来,但是已经放弃了希望,因为可靠的事情似乎都取决于虚拟内存的可用性,以及干净地挂起线程。
据我所知你不能真的只是暂停使用pthreads的其他线程。 你必须在你的第二个线程中有东西来检查应该使用类似条件变量的东西暂停的时间。 这是做这种事情的标准方式。
你可以使用互斥来做到这一点,伪代码将是:
While (true) { /* pause resume */ lock(my_lock); /* if this is locked by thread1, thread2 will wait until thread1 */ /* unlocks it */ unlock(my_lock); /* unlock so that next iteration thread2 could lock */ /* do actual work here */ }
POSIX中没有pthread_suspend(),pthread_resume()类型的API。
大多数条件变量可以用来控制其他线程的执行。
条件变量机制允许线程挂起执行并放弃处理器,直到某些条件成立。 一个条件变量必须总是与一个互斥量相关联,以避免由一个线程准备等待的竞争条件和另一个可能在第一个线程实际等待之前发信号的线程导致死锁。
欲了解更多信息
并行线程
Linux教程Posix线程
如果可以使用进程,则可以将作业控制信号(SIGSTOP / SIGCONT)发送到第二个进程。 如果您仍想共享这些进程之间的内存,则可以使用SysV共享内存(shmop,shmget,shmctl …)。
即使我自己没有尝试过,也可能使用低级别的clone()系统调用来产生不共享信号的线程。 有了这个,你可能能够发送SIGSTOP和SIGCONT到另一个线程。
不知道你是否会喜欢我的答案。 但是你可以这样做。
如果它是一个单独的过程而不是一个线程 , 我有一个解决方案 (这可能甚至有效的线程,也许有人可以分享你的想法) 使用信号 。
目前没有系统暂停或恢复进程的执行。 但是,你可以建立一个。
我会做,如果我想在我的项目中的步骤:
为第二个进程注册信号处理程序。
在信号处理程序内部,等待一个信号量。
每当你想暂停另一个进程时,只需发送一个信号
你注册了另一个进程。 程序将进入睡眠状态。
当你想恢复过程时,你可以再发送一个不同的信号。 在信号处理程序内部,您将检查信号量是否被锁定。 如果它被锁定,你将释放信号量。 所以
过程2将继续执行。
如果你能实现这一点,请分享你的feedack,如果它为你工作或没有。 谢谢。
为了在一个线程上实现暂停,你需要等待一些事件的发生。 等待旋转锁互斥是CPU周期浪费。 恕我直言,这种方法不应该遵循,因为CPU周期可能已被其他进程/线程用完。 等待一个非阻塞描述符(管道,套接字或其他)。 可以看到使用管道进行线程间通信的示例代码以上解决方案非常有用,前提是您的第二个线程拥有来自多个来源的更多信息,而不仅仅是暂停和恢复信号。 顶级的select / poll / epoll可以用在非阻塞描述符上。 您可以指定select / poll / epoll系统调用的等待时间,只有那么多微秒的CPU周期将被浪费。 我提到了这个解决方案,希望你的第二个线程有更多的事情或事件来处理,而不是暂停和恢复。 对不起,如果它比你问的更详细。
另一个更简单的方法是在这些线程之间建立一个共享的布尔变量。 主线程是变量的写者,0表示停止。 1 – 表示继续第二个线程只读取变量的值。 要实现'0'状态,使用usleep进行sime微秒,然后再次检查值。 假设,在您的设计中,几微秒的延迟是可以接受的。 执行'1' – 在完成一定的操作后检查变量的值。 否则,您也可以执行从“1”到“0”状态的信号。
你可以简单地通过信号挂起一个线程
pthread_mutex_t mutex; static void thread_control_handler(int n, siginfo_t* siginfo, void* sigcontext) { // wait time out pthread_mutex_lock(&mutex); pthread_mutex_unlock(&mutex); } // suspend a thread for some time void thread_suspend(int tid, int time) { struct sigaction act; struct sigaction oact; memset(&act, 0, sizeof(act)); act.sa_sigaction = thread_control_handler; act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; sigemptyset(&act.sa_mask); pthread_mutex_init(&mutex, 0); if (!sigaction(SIGURG, &act, &oact)) { pthread_mutex_lock(&mutex); kill(tid, SIGURG); sleep(time); pthread_mutex_unlock(&mutex); } }