4

我正在阅读 Programming With POSIX Threads (by 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 库的情况下是否有任何更改是全局可见的。

4

1 回答 1

1

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

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

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

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

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

于 2013-08-23T14:26:53.313 回答