内存可见性通过pthread库?

时间:2013-08-23 12:58:27

标签: c linux gcc pthreads

我正在阅读使用POSIX线程编程(由David Butenhof编写),他通过使用pthread库提到:

  

线程在解锁互斥锁时可以看到的内存值是什么,   无论是直接还是通过等待条件变量,也可以   后来锁定相同互斥锁的任何线程都可以看到。再次,数据   在互斥锁解锁后写的可能不一定被看到   即使在锁定之前发生写入,也会锁定互斥锁的线程。

突然之间,我想知道以下代码是否有效:

主题A:

strcpy(buffer, "hello world");
pthread_spin_lock(&lock); // assuming the mutex in the statement above can be interchanged with spinlock. I don't see why it can't
pthread_spin_unlock(&lock);

主题B:

pthread_spin_lock(&lock);
pthread_spin_unlock(&lock);
// read buffer; assuming thread B has a copy of the pointer somehow

我的问题是:线程B可以在缓冲区中看到“hello world”吗?基于他的陈述,它应该。我理解“通常”的方法是通过锁保护共享的“资源”。但是我们假设strcpy()在一个随机时间发生,它只能在程序的生命周期中发生一次,让我们假设线程B在线程A调用pthread_spin_unlock()之后以某种方式调用pthread_spin_lock():)

附带问题:是否有更快的方法使缓冲区的变化对其他线程可见?假设可移植性不是问题,我在CentOS上。我能想到的一个替代方案是使用mmap(),但不确定在不使用pthread库的情况下是否全局可见更改。

1 个答案:

答案 0 :(得分:1)

我认为您没有正确理解这一点:锁不会神奇地传输数据,它们是线程之间的一种通信形式,允许您安全地移动数据。

在你的问题中,你做了很多假设。事实上,只要您的假设都成立,如果锁不存在,您编写的所有内容都同样如此。并发编程的问题在于,一般来说,你不能做出那样的假设

如果线程A对内存进行了更改,那么它将立即可见到线程B (允许缓存和编译器优化的变幻莫测)。无论是否有锁,这都是正确的。但是,如果没有锁定,就无法保证写入完成,甚至开始。

您首先假设(要求)您只使用锁定集写入共享数据。最后一部分告诉你如果你先尝试不锁定就会发生什么不好的事情。

我不确定“即使写入发生在锁定之前”也意味着什么,但它可能指的是困扰并发程序的各种竞争条件和内存缓存效应。锁可能实际上不会传输数据,但它们将被编码,以便它们强制编译器在调用中同步存储器(“内存屏障”)。