当前位置:  开发笔记 > 编程语言 > 正文

C++线程,共享数据

如何解决《C++线程,共享数据》经验,为你挑选了4个好方法。

我有一个应用程序,其中2个线程正在运行...当我从一个线程更改一个全局变量时,是否有任何证据,另一个会注意到这个变化?我没有任何同步或互斥系统......但是这段代码应该一直工作(想象一下名为dataUpdated的全局bool):

线程1:

while(1) {
    if (dataUpdated)
        updateScreen();
    doSomethingElse();
}

线程2:

while(1) {
    if (doSomething())
        dataUpdated = TRUE;
}

像gcc这样的编译器是否以不检查全局值的方式优化此代码,只在编译时考虑它的值(因为它会在同一个thred中更改)?

PS:对于类似游戏的应用程序而言,在写入值时是否会有读取真的无关紧要......重要的是这个更改会被其他线程注意到.



1> puetzk..:

是.不,也许吧.

首先,正如其他人提到的那样,你需要使dataUpdated易变; 否则编译器可以自由地将其读出循环(取决于它是否可以看到doSomethingElse不接触它).

其次,根据您的处理器和订购需求,您可能需要内存屏障.volatile足以保证其他处理器最终会看到更改,但不足以保证更改将按照执行顺序进行.你的例子只有一个标志,所以它并没有真正显示出这种现象.如果您需要并使用内存屏障,则不再需要volatile

挥发性被认为是有害的,Linux内核内存障碍是潜在问题的良好背景; 我真的不知道有什么类似的专门针对线程编写的.值得庆幸的是,线程并不像硬件外设那样经常引起这些问题,尽管你描述的情况(指示完成的标志,如果设置了标志,其他数据被认为是有效的)正是排序的事情. matterns ...



2> 1800 INFORMA..:

以下是使用boost条件变量的示例:

bool _updated=false;
boost::mutex _access;
boost::condition _condition;

bool updated()
{
  return _updated;
}

void thread1()
{
  boost::mutex::scoped_lock lock(_access);
  while (true)
  {
    boost::xtime xt;
    boost::xtime_get(&xt, boost::TIME_UTC);
    // note that the second parameter to timed_wait is a predicate function that is called - not the address of a variable to check
    if (_condition.timed_wait(lock, &updated, xt))
      updateScreen();
    doSomethingElse();
  }
}

void thread2()
{
  while(true)
  {
    if (doSomething())
      _updated=true;
  }
}



3> Niall..:

使用锁.始终使用锁来访问共享数据.将变量标记为volatile将阻止编译器优化内存读取,但不会阻止其他问题,例如内存重新排序.没有锁定,无法保证doSomething()中的内存写入将在updateScreen()函数中可见.

唯一的另一种安全方法是使用内存栅栏,例如显式或隐式使用Interlocked*函数.



4> Tall Jeff..:

使用volatile关键字向编译器提示值可以随时更改.

volatile int myInteger;

以上内容将保证对变量的任何访问都将在没有任何特定优化的情况下进出内存,因此在同一处理器上运行的所有线程将"看到"变量的变化与代码读取的语义相同.

Chris Jester-Young指出,在多处理器系统中可能出现对这种可变值变化的一致性问题.这是一个考虑因素,它取决于平台.

实际上,相对于平台而言,有两个需要考虑的因素.它们是记忆事务的一致性和原子性.

原子性实际上是单处理器和多处理器平台的考虑因素.出现这个问题是因为变量本质上可能是多字节的,问题是一个线程是否可以看到值的部分更新.即:一些字节改变,上下文切换,通过中断线程读取无效值.对于处于自然机器字大小或更小且自然对齐的单个变量不应该是一个问题.具体来说,只要对齐,int类型在这方面应该总是正常 - 这应该是编译器的默认情况.

相对于一致性,这是多处理器系统中的潜在问题.问题是系统是否在处理器之间实现完全缓存一致性.如果实现,通常使用硬件中的MESI协议来完成.这个问题没有说明平台,但是英特尔x86平台和PowerPC平台在处理器之间对于正常映射的程序数据区域是高速缓存一致的.因此,即使存在多个处理器,这种类型的问题也不应该成为线程之间的普通数据存储器访问的问题.

与出现的原子性相关的最后一个问题特定于读 - 修改 - 写原子性.也就是说,如果一个值被读取更新的值和写入,你如何保证这是原子地发生,甚至跨处理器,如果不止一个.因此,为了在没有特定同步对象的情况下工作,将要求访问变量的所有潜在线程仅是读者,但期望一次只有一个线程可以成为写入者.如果不是这种情况,那么您确实需要一个可用的同步对象,以确保对变量进行读 - 修改 - 写操作的原子操作.

推荐阅读
ERIK又
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有