c++ - 线程同步问题

标签 c++ multithreading

在下面的示例中,我最终为两个线程调用了 pthread_join()(在我打印总和之前)。尽管预计总和应为 0,但它会打印任何值。我知道如果我在创建第二个线程之前执行 pthread_join(id1,NULL) 那么它会工作正常(确实如此),但我不明白为什么当我最后为两个线程调用 join。

因为 sum 仅在两个线程必须完全执行完毕后才会打印。因此,在第一个线程执行后,它必须将 2000000 添加到变量 sum,第二个线程必须从总和中减去 2000000 sum 应该为 0

long long sum=0;

void* counting_thread(void* arg)
{   
    int offset = *(int*) arg;
    for(int i=0;i<2000000;i++)
    {
        sum=sum+offset;
    }
    pthread_exit(NULL);
}
int main(void)
{
    pthread_t id1;
    int offset1 = 1;
    pthread_create(&id1,NULL,counting_thread,&offset1);

    pthread_t id2;
    int offset2 = -1; 
    pthread_create(&id2,NULL,counting_thread,&offset2);

    pthread_join(id1,NULL);
    pthread_join(id2,NULL);

    cout<<sum;
}

最佳答案

问题是 sum=sum+offset;不是线程安全的。

这导致一些金额未被计算在内。

正如您指定的 C++,std::atomic<long long> sum;会有所帮助,但您需要使用 +=运算符,而不是线程不安全的 sum = sum + count;

sum += offset;

阻止更新的互斥体也会有所帮助。

如果没有这些更改,编译器可以生成代码,这

  • 阅读 sum在函数的开头,只有一个线程应用它的更改。
  • 旧值为 sum用于添加。
  • 缓存中的状态不正确。

阅读优化

编译器可以在线程启动的时候合法的读取sum的值,加上n次offset,存储这个值。这意味着只有一个线程可以工作。

陈旧的值(value)

考虑以下汇编代码。

read sum
add offset to sum
store sum

thread1                     thread2
1 read sum                     
2 add offset to sum            read sum
3 store sum                    add offset to sum
4 read sum                     store sum
5 add offset to sum            read sum
6 store sum                    add offset to sum

线程 2 的第 3 行将偏移量添加到旧值,这使得线程 1 的第 3 行丢失。

缓存中的状态不正确

在多线程系统中,进程的线程之间缓存可能不一致。

这意味着即使在 sum+=offset 之后已经执行,那么另一个核心/CPU 可能会看到预先更新的值。

这允许 CPU 运行得更快,因为它们可以忽略它们之间的数据共享。但是,当 2 个线程正在访问相同的数据时,需要考虑这一点。

std::atomic/mutex 确保:-

  1. 该值是原子修改的(就好像 sum = sum + count 是不可分割的)。
  2. 值(value)在所有核心/CPU 中始终可见。
  3. 编译器不会重新排序 sum 的加载/存储,就好像它无法更改一样。

关于c++ - 线程同步问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33331864/

相关文章:

c++ - 在 C++ 中将数据从一个线程发送到另一个线程的最快方法是什么?

java - 用于频繁更新的 CopyOnwriteArrayList 替代方案

c++ - 如何在 C++ 中完成行后删除间距?

c++ - 前向声明库名称

c++ - 将句子拆分为包含撇号的单词

java - DelayQueue 意外行为。 DrainTo 仅从队列中删除 1 个过期项

java - 从独立 native 代码调用 java 代码

java - 什么是 C++ deque 的 Java 等价物?

python - 如何刷新 PyGTK 中的 DrawingArea?

java - 向 hashmap 添加值时出现 ConcurrentModificationException