如何确保线程读取最后一个变量值?

时间:2014-08-12 07:40:04

标签: c multithreading pthreads sync

我有一个多线程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之前的互斥锁定/解锁解决方案应该可以工作,但我想知道如何避免它,因为我已经确保没有并发访问变量,这要归功于我所拥有的控制权具有挂起/恢复机制的线程?

3 个答案:

答案 0 :(得分:1)

显然,您需要确保线程4中的S写入在从屏障释放时对其他线程可见 - 而不是之前。令人高兴的是,自定义屏障具有互斥锁,barrier_continue()在释放工作线程时获取并释放它。当工人重新启动时,他们将获得并释放互斥锁。因此,如果操作顺序是:

,那么事情就会奏效
  1. 所有工作线程pthread_cond_wait()(在互斥锁下);
  2. 主题4 然后获取互斥锁并写入S;
  3. 主题4按pthread_broadcast();
  4. 重新启动工作人员
  5. 主题4释放互斥锁;
  6. 所有工作人员(重新)获取并释放互斥锁并阅读S
  7. ...因为互斥锁的获取和释放是同步点。 (实际上,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中的示例)