简体   繁体   English

互斥锁会锁定内存的哪一部分? (p线程)

[英]What part of memory does a mutex lock? (pthreads)

All the documentation I've read on the pthreads mutex states only that a mutex prevents multiple threads from accessing shared memory, but how do you specify in the program what exactly is that? 我在pthreads互斥锁上阅读的所有文档仅指出,互斥锁可防止多个线程访问共享内存,但是您如何在程序中指定确切的含义呢? Is it all the global variables in the program, the variables being accessed between the locking and unlocking functions, or... ? 是程序中的所有全局变量,还是在锁定和解锁功能之间访问的变量,还是...? Everything I've found on pthreads, including the examples, is irritatingly vague. 我在pthreads上发现的所有内容(包括示例)都非常令人困惑。

a mutex prevents multiple threads from accessing shared memory 互斥锁可防止多个线程访问共享内存

The above is an incorrect statement. 以上是不正确的陈述。 By itself, a mutex does not do that. 就其本身而言,互斥体不会这样做。 It lets you build code that prevents multiple threads from accessing shared memory or other resources concurrently, but it does not lock anything by itself. 它使您可以构建代码,以防止多个线程同时访问共享内存或其他资源,但它本身不会锁定任何内容。

You can build a program that uses a mutex to prevent multiple threads from executing specific pieces of code concurrently. 您可以构建一个使用互斥量来防止多个线程同时执行特定代码的程序。 If these pieces of code happen to be accessing a shared memory region, and no other code would try accessing that region concurrently without locking the mutex, then the effect would be that of "locking" that region of memory. 如果这些代码段恰好正在访问共享内存区域,并且没有其他代码会尝试在不锁定互斥锁的情况下并发访问该区域,那么结果将是“锁定”该内存区域。

A mutex doesn't lock memory, it "locks" a part of the execution path, and synchronizes memory (but when locking and when unlocking). 互斥锁不会锁定内存,而是“锁定”执行路径的一部分,并同步内存(但在锁定和解锁时)。 What is guaranteed is that if one thread holds the mutex, no other threads can acquire it, and any thread attempting to acquire it will be blocked until it is released. 可以保证的是,如果一个线程持有该互斥锁,则其他线程无法获取该互斥锁,并且任何试图获取该互斥锁的线程都将被阻塞,直到被释放。

It is also guaranteed that any memory accesses (read or write) will be ordered with respect to acquiring or releasing the mutex; 还可以保证将就获取或释放互斥锁对任何内存访问(读或写)进行排序。 in other words, that any reads made while the mutex is held will reflect any changes made before the mutex was acquired (including those made in a different thread), and that any modifications made while the mutex is held will be potentially visible to all other threads at the latest when the mutex is released. 换句话说,在保持互斥锁的同时进行的任何读取都将反映在获取互斥锁之前所做的任何更改(包括在其他线程中进行的更改),并且在保持互斥锁的同时进行的任何修改都可能对其他所有对象可见互斥锁释放时最晚线程化。 (The other threads will, of course, have to ensure that their memory reads see up to date values for this to work.) (当然,其他线程必须确保其内存读取可以使用最新的值,以使其正常工作。)

For more information, you really should read Programming with POSIX Threads , by David Butenhof. 有关更多信息,您确实应该阅读David Butenhof撰写的《 使用POSIX线程编程 》。 It's the reference, and explains them in detail. 它是参考,并对其进行了详细说明。

Strictly speaking, a mutex only locks/unlocks itself. 严格来说,互斥锁只能锁定/解锁自身。 What shared resources it protects depends entirely on how you use it. 它保护哪些共享资源完全取决于您的使用方式。 You use mutexes (or more generally any synchronisation primitives) to establish a protocol for yourself to safely access shared resources such as data. 您可以使用互斥锁(或更普遍地说,是任何同步原语)来建立协议,以安全地访问共享资源(例如数据)。

For example, you have an array double d[10] which is to be access by different threads. 例如,您有一个数组double d[10] ,该数组将由不同的线程访问。 To protect this from concurrent modifications, you can create one mutex, let's say mutex_for_d , and program your code so that every time any code accesses d , it will lock mutex_for_d first. 为了保护它免受并发修改的影响,您可以创建一个互斥锁(例如, mutex_for_d ,然后对代码进行mutex_for_d ,以便每次任何代码访问d ,它都将首先锁定mutex_for_d That way, access to d is protected by the mutex. 这样,对d访问将受到互斥锁的保护。

Alternatively, you could decide that each element of the array will be synchronised separately - and have an array of mutexes, always locking the one for the element you access. 另外,您可以决定将数组中的每个元素分别同步-并拥有一个互斥体数组,始终为您要访问的元素锁定一个互斥体。

This is purely your own protocol and you must make sure you stick to it - if you forget to lock the mutex in one function which modifies d , the program will still run, but can potentially introduce a data race. 这纯粹是您自己的协议,必须确保遵守该协议-如果忘记将互斥锁锁定在修改d一个函数中,则该程序仍将运行,但有可能导致数据争用。 For this reason, you will normally want to hide shared data behind a class interface which will guarantee correct locking, something like this: 因此,您通常希望将共享数据隐藏在类接口后面,以保证正确锁定,如下所示:

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;
};

See this code: 参见以下代码:

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];
}

As you can see, the variables initialized_array and some_array are deeply related, but the relationship exists only in the code that handles them both. 如您所见,变量initialized_arraysome_array是密切相关的,但是这种关系仅存在于处理它们的代码中。

That's how mutexes are associated with shared memory; 这就是互斥锁与共享内存的关联方式。 the association happens because you write code that does so. 发生这种关联是因为您编写了这样做的代码。 There is no way to say "this mutex protects that shared object", the programmer has to make sure every time the shared object is accessed by a thread, it also performs the synchronization on the correct mutex. 没有办法说“此互斥锁保护该共享库”,程序员必须确保每次线程访问共享库时,它还要在正确的互斥锁上执行同步。

When locked, a mutex prevents any other thread from obtaining a lock on that same mutex. 锁定后,互斥锁会阻止其他任何线程获得对该同一互斥锁的锁定。 So, if you want some particular data to be thread safe (ie, a critical section of memory), you should obtain a lock on the mutex before reading from it or writing to it, then release the lock when finished. 因此,如果您希望某些特定的数据是线程安全的(即内存的关键部分),则应在互斥锁读取或写入之前获取该互斥锁的锁定,然后在完成后释放该锁定。 The mutex itself does not refer to any particular section of memory. 互斥锁本身并不引用内存的任何特定部分。 It is simply a tool you can use. 它只是您可以使用的工具。

Mutex locks a piece of code. Mutex锁定一段代码。 For example: 例如:

mutex.lock();
    //some code here
mutex.unlock();

If one thread enters the code above it locks it, until it is done with it. 如果一个线程在其上面输入了代码,则它将锁定它,直到完成它。 At the same time no other thread can execute this piece of code. 同时,没有其他线程可以执行这段代码。

mutex and threads independence 互斥锁和线程独立

A mutex locks itself and that's all it locks. 互斥锁会锁定自身 ,仅此而已。 It does not lock other memory, it does not lock code. 它不会锁定其他内存,也不会锁定代码。 You can design your code so that something other than just the mutex is protected but that's down to how you design the code, not a feature of the mutex itself. 您可以设计代码,以便保护互斥锁以外的其他东西,但这取决于您设计代码的方式,而不是互斥锁本身的功能。

You can tell it doesn't lock data memory because you can freely modify the memory when the mutex is locked by someone else just by not using the mutex: 您可以说它不会锁定数据内存,因为当互斥锁被其他人锁定时,可以通过不使用互斥锁来自由地修改内存:

thread1:            thread2:
    lock mtx            set i to 4  // i is not protected here
    set i to 7
    unlock mtx

To say it locks code is also not quite right since you can run all sort of different sections of code under the control of a single mutex. 说它锁定代码也不是很正确,因为您可以在单个互斥锁的控制下运行各种不同的代码部分。

And, if someone manages to get to the code within a mutex block without first claiming the mutex, it can freely run the code even when someone else has the mutex locked: 而且,如果某人设法在不首先声明互斥锁的情况下访问了互斥锁块中的代码,即使有人将互斥锁锁定,它也可以自由地运行代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM