Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 互斥锁锁定内存的哪一部分?(pthreads)_C++_Multithreading_Pthreads - Fatal编程技术网

C++ 互斥锁锁定内存的哪一部分?(pthreads)

C++ 互斥锁锁定内存的哪一部分?(pthreads),c++,multithreading,pthreads,C++,Multithreading,Pthreads,我读过的关于pthreads互斥体的所有文档都只说明互斥体阻止多个线程访问共享内存,但是如何在程序中指定这到底是什么?是程序中的所有全局变量,在锁定和解锁功能之间访问的变量,还是?我在pthreads上发现的所有内容,包括示例,都非常模糊。参见以下代码: bool initialized_array = false; int some_array[10]; void do_some_initialization() { ... }; int get_array_element(int i)

我读过的关于pthreads互斥体的所有文档都只说明互斥体阻止多个线程访问共享内存,但是如何在程序中指定这到底是什么?是程序中的所有全局变量,在锁定和解锁功能之间访问的变量,还是?我在pthreads上发现的所有内容,包括示例,都非常模糊。

参见以下代码:

bool initialized_array = false;

int some_array[10];

void do_some_initialization() { ... };

int get_array_element(int i)
{
    if (!initialized_array) {
        do_some_initialization();
        initialized_array = true;
    }
    return some_array[i];
}
如您所见,变量
initialized_array
some_array
之间有着密切的关系,但这种关系只存在于处理这两个变量的代码中


这就是互斥体与共享内存的关联方式;这种关联之所以发生,是因为您编写了这样做的代码。没有办法说“此互斥体保护该共享对象”,程序员必须确保每次线程访问该共享对象时,它也会在正确的互斥体上执行同步。

锁定时,互斥体会阻止任何其他线程在同一互斥体上获得锁。因此,如果您希望某些特定数据是线程安全的(即内存的关键部分),那么您应该在读取或写入互斥锁之前获得互斥锁,然后在完成时释放锁。互斥锁本身并不引用内存的任何特定部分。它只是一个您可以使用的工具。

互斥锁不锁定内存,它“锁定”执行的一部分 路径,并同步内存(但在锁定和 解锁)。可以保证的是,如果一个线程持有 互斥,没有其他线程可以获取它,任何线程 试图获取它将被阻止,直到它被释放

还保证任何内存访问(读或写) 将就获取或发布 互斥;换句话说,当互斥锁被激活时进行的任何读取 HOLD将反映在获取互斥锁之前所做的任何更改 (包括用不同螺纹制成的),以及 在保持互斥锁时所做的修改可能会丢失 最迟在禁用互斥时对所有其他线程可见 释放。(当然,其他线程必须确保 他们的内存读取可以查看最新的值以使其正常工作。)

有关更多信息,您确实应该阅读POSIX线程编程, 大卫·布滕霍夫著。这是参考资料,并详细解释了它们

互斥锁阻止多个线程访问共享内存

上述说法是不正确的。互斥本身并不能做到这一点。它允许您构建代码,防止多个线程同时访问共享内存或其他资源,但它本身不会锁定任何内容


您可以构建一个使用互斥锁的程序,以防止多个线程同时执行特定的代码段。如果这些代码碰巧正在访问共享内存区域,并且没有其他代码会在不锁定互斥锁的情况下尝试同时访问该区域,那么效果将是“锁定”该内存区域。

互斥锁锁定一段代码。例如:

mutex.lock();
    //some code here
mutex.unlock();
如果一个线程输入上面的代码,它将锁定它,直到它完成。同时,没有其他线程可以执行这段代码

互斥锁自身锁定,仅此而已。它不会锁定其他内存,也不会锁定代码。您可以设计您的代码,以便保护互斥体以外的内容,但这取决于您如何设计代码,而不是互斥体本身的功能

您可以知道它不会锁定数据内存,因为当互斥锁被其他人锁定时,您可以通过不使用互斥锁来自由修改内存:

thread1:            thread2:
    lock mtx            set i to 4  // i is not protected here
    set i to 7
    unlock mtx
说它锁定代码也不太正确,因为您可以在一个互斥锁的控制下运行各种不同的代码段

而且,如果有人能够在不首先声明互斥对象的情况下访问互斥对象块中的代码,那么即使其他人锁定了互斥对象,它也可以自由运行代码:

threadN:
    if thread_id == 2: goto skip_label1
    lock mtx
  :skip1_label1

    set i to 7              // not as protected as you think

    if thread_id == 2: goto skip_label2
    unlock mtx
  :skip1_label2

严格地说,互斥锁只会锁定/解锁自身。它所保护的共享资源完全取决于您如何使用它。您可以使用互斥体(或者更一般地说,任何同步原语)为自己建立一个协议,以安全地访问共享资源,如数据

例如,您有一个数组
double d[10]
,可由不同的线程访问。为了防止并发修改,您可以创建一个互斥体,比如说
mutex\u for_d
,并对代码进行编程,以便每次任何代码访问
d
,它都会首先锁定
mutex\u for_d
。这样,对
d
的访问就受到互斥锁的保护

或者,您可以决定阵列的每个元素将分别进行同步,并拥有一个互斥体阵列,始终锁定您访问的元素的互斥体

这纯粹是您自己的协议,您必须确保遵守它-如果您忘记在修改
d
的一个函数中锁定互斥锁,程序仍将运行,但可能会引入数据竞争。因此,您通常希望将共享数据隐藏在类接口后面,以保证正确锁定,如下所示:

struct SharedArray
{
  double get(size_t idx) const { std::lock_guard<std::mutex> lock(mut); return d[idx]; }
  void set(size_t idx, double v) { std::lock_guard<std::mutex> lock(mut); d[idx] = v; }
private:
  double d[10];
  std::mutex mut;
};
struct SharedArray
{
双get(size_t idx)const{std::lock_guard lock(mut);返回d[idx];}
空集(size_t idx,double v){std::lock_guard lock(mut);d[idx]=v;}
私人:
双d[10];
std::互斥mut;
};

由您决定。一般来说,您锁定一个互斥锁,操纵一个特定的变量,然后解锁互斥锁。互斥锁调用之后和解锁调用之前的代码部分称为关键部分。不管你在代码中做什么。@fayyazkl所以我只是锁定互斥锁,处理一些变量,所有这些变量都被锁定了?就像编译器或者其他什么东西一样,根据我在那部分代码中使用的变量来锁定内存的哪些部分