2+线程写/读变量的真正危险

同时读/写单个变量的真正危险是什么?

如果我使用一个线程来写一个变量而另一个线程用来读取while循环中的变量,并且如果在写入时读取变量并且使用旧值没有危险,那么还有什么危险呢?

同时读/写是否会导致线程崩溃或者在发生精确的同时读/写时在低电平上发生什么?

如果两个线程在没有适当同步的情况下访问变量,并且这些访问中至少有一个是写入,那么您将拥有数据争用和未定义的行为。

未定义的行为如何表现完全取决于实现。 在大多数现代架构中,您不会从硬件中获得陷阱或exception或任何东西,它会读取内容或存储内容。 问题是,它不一定会读或写你所期望的。

例如,如果有两个线程递增变量,您可能会错过计数,如我在devx的文章中所述: http : //www.devx.com/cplus/Article/42725

对于单个编写器和单个读取器,最常见的结果是读者看到过时值,但如果更新需要多个循环,或者变量跨缓存行分割,您可能还会看到部分更新的值。 然后会发生什么取决于你用它做什么 – 如果它是一个指针并且你得到一个部分更新的值然后它可能不是一个有效的指针,并且不会指向你想要它的东西,然后你可能由于解除引用无效指针值而导致任何类型的损坏或错误。 如果错误的指针值恰好指向内存映射的I / O寄存器,这可能包括格式化硬盘或其他不良后果….

通常,您会得到意想不到的结果 维基百科定义了两种不同的比赛条件

当内部变量的更改顺序决定状态机最终进入的最终状态时,就会发生严重竞争。

当内部变量的更改顺序不会改变最终状态时,就会发生非关键竞争。 换句话说,当移动到期望状态时发生非关键竞争意味着必须一次改变多个内部状态变量,但无论这些内部状态变量以何种顺序改变,结果状态都将是相同的。

所以输出不会总是弄乱,这取决于代码。 最好始终处理竞争条件以便以后进行代码扩展并防止可能的错误。 没有什么比不相信自己的数据更烦人了。

读取相同值的两个线程完全没问题。

当一个线程写入非primefaces变量而另一个线程读取它时,问题就开始了。 然后读取的结果是不确定的。 由于线程可能随时被抢占(停止)。 只保证对primefaces变量的操作是不可破坏的。 primefaces操作通常写入int类型变量。

如果您有两个线程访问相同的数据,最佳做法+通常不可避免地使用锁定(互斥,信号量)。

心连心

马里奥

最糟糕的情况取决于实施。 有很多完全独立的pthread实现,运行在不同的系统和硬件上,我怀疑任何人都知道所有这些。

如果p不是指向volatile的指针,那么我认为允许符合Posix实现的编译器转向:

 while (*p == 0) {} exit(0); 

进入*p的单个检查,然后是一个无限循环,根本不打扰查看*p的值。 在实践中,它不会,所以这是一个问题,你是否想要编程到标准,或编程到你正在使用的实现的无证件观察行为。 后者通常适用于简单的情况,然后你构建代码,直到你做了足够复杂的事情,它意外地不起作用。

实际上,在没有连贯内存缓存的多CPU系统上,可能需要很长时间才能在循环中看到由不同CPU进行的更改,因为没有内存屏障,它可能永远不会更新其缓存的视图主记忆 但英特尔有一致的缓存,所以很可能你个人不会看到任何延迟足够长的关注。 如果一些可怜的傻瓜试图在一个更奇特的架构上运行你的代码,他们可能最终必须修复它。

回到理论,您描述的设置可能会导致崩溃。 想象一个假设的架构,其中:

  • p指向非primefaces类型,例如在典型的32位架构上long long
  • 该系统long long有陷阱表示,例如因为它有一个填充位用作奇偶校验。
  • 当读取发生时,对*p的写入是半完成的
  • 半写已更新该值的某些位,但尚未更新奇偶校验位。

Bang,未定义的行为,你读了一个陷阱表示。 可能是Posix禁止C标准允许的某些陷阱表示,在这种情况下, long long可能不是*p类型的有效示例,但我希望您可以找到允许陷阱表示的类型。

如果要写入和写入的变量无法primefaces更新或读取,则读者可能会获取损坏的“部分更新”值。

  • 您可以看到部分更新(例如,您可能会看到一个long long变量,其中一半来自新值,另一半来自旧值)。
  • 在使用内存屏障( pthread_mutex_unlock()包含隐式内存屏障)之前,无法保证看到新值。

取决于平台。 例如,在Win32上,那么对齐的32位值的读写操作是primefaces的 – 也就是说,你不能半读新值并半读旧值,如果你写,那么当有人来读,要么获得全新值,要么获得旧值。 当然,并非所有价值观或所有平台都是如此。

结果未定义。

考虑以下代码:

 global int counter = 0; tread() { for(i=0;i<10;i++) { counter=counter+1; } } 

问题是,如果你有N个线程,结果可以是10到N * 10之间的任何值。 这是因为它可能会发生所有踏板读取相同的值增加它然后写入值+1返回。 但是你问你是否可以崩溃程序或硬件。
这取决于。 在大多数情况下,错误的结果是无用的。

要解决此锁定问题,您需要互斥锁或信号量。

Mutex锁定代码。 在大写字母中,您将锁定部分代码

 counter = counter+1; 

信号量锁定变量的位置

 counter 

解决相同类型问题的基本相同的事情。

检查胎面库中的此工具。

http://en.wikipedia.org/wiki/Mutual_exclusion