【问题标题】:Will this be a non-interference in a multi-threaded environment?这在多线程环境中会不会产生干扰?
【发布时间】:2013-02-25 20:29:17
【问题描述】:
std::deque<T> dq;
Thread_function(pointer to queue as argument)     // created 8 threads
{
     vertext_found = true;
     **v is initialized to NULL
     while ( i < dq->size())
     {
          EnterCriticalSection(&h);
          if( i < dq.size() ) {
              v = dq.at(i);      // accessing element of queue without popping
              i++;
              vertext_found = true;
          }
          LeaveCriticalSection(&h);
          if (vertext_found && (i < dq.size()) && v != NULL)
          {
              **operation on 'v'
              vertext_found = false;
          }
     }
}

这是否会成为数据竞争条件,尤其是在关键部分之外处理“while (i size())”时?我的方法正确吗?否则请建议我。

【问题讨论】:

  • std::deque&lt;T&gt; dq; 真的是本地对象吗?我看到你正在访问它,就好像它是一个指针 (dq-&gt;size())
  • 看起来您只是从队列中读取。对吗?
  • 发布一个更完整的例子。你遗漏了太多信息。您的 dq 似乎是线程本地的,但您的问题暗示它不是。
  • 如果 dq 是线程间共享的,那么请说明你是否在访问的同时修改它。如果你有 8 个线程只读取队列而不进行修改,那么你根本不需要同步..
  • 我只是在读取队列.. 但需要通过不同的线程访问每个元素.. 是的,我正在将指针传递给队列

标签: c++ multithreading thread-safety deque thread-synchronization


【解决方案1】:

这在多线程环境中会不会产生干扰?

在您的问题文本中,dq(与您函数中的所有其他变量一样)是一个 local 对象:

std::deque<T> dq;

如果确实如此,那么这个问题有一个简单的答案:“是”。它是线程安全的,因为没有争用:每个线程都在一个本地对象上工作,并且由于没有共享,所以不会有任何数据竞争。


现在假设您的代码旨在显示 shared 数据结构的使用,并且 dq 实际上是一个全局对象或以某种方式可由多个线程同时访问的东西(这就是 @ 987654325@函数调用似乎暗示),那么答案是“取决于”

如果您的所有线程仅同时执行您正在显示的函数,并且dq 是对const 的引用或指针,那么您的函数不包含对任何非const 成员函数,那么答案是“是的,但是你根本不需要任何关键部分这个案例”。 C++11 标准的第 17 段 6.5.9/3 规定:

C++ 标准库函数不得直接或间接修改线程可访问的对象 (1.10) 除了当前线程,除非通过函数的非const 直接或间接访问对象 参数,包括this

对定义什么是数据竞争的第 1.10 段(尤其是 1.10/21)的引用使上述段落的含义更加清晰:

如果程序在不同线程中包含两个冲突操作,则该程序的执行包含数据竞争, 至少其中一个不是原子的,也没有发生在另一个之前。任何此类数据竞争都会导致 未定义的行为。 [...]

最后,第 1.10/4 段指定了两个操作何时发生冲突:

如果其中一个修改了内存位置 (1.7) 而另一个修改了内存位置,则两个表达式计算会发生冲突 访问或修改相同的内存位置。

由此得出的结论是 const 成员函数必须是线程安全的。您可能有兴趣观看this presentation by Herb Sutter 的相关信息。

因为deque&lt;T&gt;::size()const 成员函数,而at()const 成员函数(因为您是从引用或指向const 的指针调用它)返回对const 的引用,不需要同步来自多个线程的访问。


如果您的dq 不是指向const的引用或指针,那么答案是“”,因为@ 987654340@ 是非const 成员函数。此外,由于v 是对元素的非常量引用,因此您的“对v 的操作”可能不是const,因此在@ 的元素 上引入了数据竞争987654345@ 而不是dq 本身。

同样,如果你的线程同时通过其他函数访问和修改dq,那么答案又是“否”,因为你没有保护所有的访问共享对象。读操作与写操作冲突(见上文),您只是保护其中的一些。在这种情况下,您的临界区应该跨越整个while 循环。

【讨论】:

  • @Andy.. 编辑了我的原始帖子.. 我没有修改(删除或写入)队列。我只是在访问/读取队列的元素。但是没有两个线程应该访问队列的同一个元素。有时程序执行得很好,但有时在“** operation on 'v'”处出现“访问冲突读取位置错误”。可能是什么问题?
  • @Hello:您只是在访问这些元素吗?或者你正在修改它们?如果您只是访问它们,那么所有const 函数都应该是线程安全的,这意味着您可以让dq 成为const 的引用或指针。在这种情况下,您根本不需要关键部分。如果您正在修改这些元素,那么关键部分也应该包含“对 v 的操作”。请注意,由于您从不修改队列,因此多余的 if (i &lt; dq.size()) 是无用的。
猜你喜欢
  • 1970-01-01
  • 2016-12-19
  • 2016-04-10
  • 1970-01-01
  • 1970-01-01
  • 2018-11-17
  • 1970-01-01
  • 2012-07-25
  • 2011-04-04
相关资源
最近更新 更多