我有一个多线程C应用程序如下(其中S是一个全局共享变量):
Thread 1 Thread 2 Thread 3 Thread 4
while(1) while(1) while(1) while(1)
read S read S read S
| | | sleep 1 second
| | | stop all other threads
| | | write to share variable S
| | | resume all other threads
read S read S read S
| | |
| | |
barrier barrier barrier
它运行在不同英特尔多核架构上的3.11 linux内核之上。
正如上一个问题How to properly suspend threads?中所建议的,我正在使用自定义屏障来暂停/恢复我的线程。线程1到3在其无限循环的主体中多次读取共享变量S.我的问题是,如何确保当它们重新启动时,它们都会读取线程4在无限循环开始时写入的最后一个值?
我想在读取和写入S之前的互斥锁定/解锁解决方案应该可以工作,但我想知道如何避免它,因为我已经确保没有并发访问变量,这要归功于我所拥有的控制权具有挂起/恢复机制的线程?
答案 0 :(得分:1)
显然,您需要确保线程4中的S
写入在从屏障释放时对其他线程可见 - 而不是之前。令人高兴的是,自定义屏障具有互斥锁,barrier_continue()
在释放工作线程时获取并释放它。当工人重新启动时,他们将获得并释放互斥锁。因此,如果操作顺序是:
pthread_cond_wait()
(在互斥锁下); S
; pthread_broadcast()
; S
。...因为互斥锁的获取和释放是同步点。 (实际上,3和4可以按照其他顺序完成。)
为了实现这一点,当线程4决定暂停工作线程时,它需要一种方法然后等待它们全部停止,这样它就可以写S
并重新启动工作线程。这是你的"停止所有其他线程"之后的额外步骤,在那里你等待所有其他线程停止"。这也涉及锁定自定义屏障互斥锁......所以实际上不需要额外的锁定。
这里的问题不是确保在重新启动之后工作人员可以看到S
的写入,问题是确保新的S
在停止之前 您可以拥有一个Next_S
变量,工作人员在重新启动后会将其拾取。线程4可以"停止所有其他线程",写入Next_S
然后重新启动所有工作者。重启后,工作人员可以阅读Next_S
,而不是之前。
答案 1 :(得分:0)
即使您暂停线程并且不会发生并发访问,您仍然需要告诉编译器该值可能异步更改。如果您可以使用C11并且S
具有类似int
的简单类型,则可以使用atomic_int
并节省将线程置于睡眠状态并将其唤醒的开销。
我不确定previous answer是否线程在定义的点暂停,而不是在读取S
的一半之后暂停。假设从未发生以下情况应该是安全的,即使我已经感受到了强烈抗议:由于S
上无法进行数据竞争,您只需要阻止编译器将S
存储在寄存器中即可make S
volatile
或通过volatile
指针访问它。如果您使用S
来同步其他数据,则无效,但它本身适用于S
。
答案 2 :(得分:0)
如果您正在使用pthread(在C ++ 11之前),您可以在访问共享变量之前使用posix信号量锁并解锁,使用pthread_mutex_lock和pthread_mutex_unlock(例如http://www.cs.uiuc.edu/class/sp06/cs241/Discussions/cs241-ds3.pdf中的示例)