c-通过pthread库的内存可见性



我正在阅读《用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能在缓冲区中看到"你好世界"吗?根据他的发言,应该是这样。我知道"通常"的方法是通过锁定来保护共享的"资源"。但是,让我们假设strcpy()发生在一个随机的时间,并且它在程序的生命周期中只能发生一次,并且让我们假设线程B在线程a调用pthread_spin_unlock()之后以某种方式调用pthread _spin_lock():)

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

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

在你的问题中,你做了很多假设。事实上,如果锁不存在,只要你的假设都成立,那么你所写的一切都将同样正确。并发编程的问题是,通常情况下,不能做出这样的假设

如果线程A对内存进行了更改,则它对线程B立即变得可见(考虑到缓存和编译器优化的不确定性)。无论有没有锁,这都是正确的。但是,如果没有锁,就无法保证写入完成,甚至无法开始。

您首先得到的报价假设(要求)您只写入具有锁集的共享数据。最后一部分告诉如果你试图在没有锁定的情况下先写,会发生什么不好的事情。

我不确定"即使写入发生在锁定之前"的确切含义,但它可能指的是困扰并发程序的各种竞争条件和内存缓存效应。锁实际上可能不会传输数据,但它们会被编码,从而迫使编译器在调用中同步内存("内存屏障")。

最新更新