我试图理解互斥是如何工作的。做了很多谷歌搜索,但它仍然留下了一些疑问,它是如何工作的,因为我创建了自己的程序,其中锁定不工作。

One absolutely non-intuitive syntax of the mutex is pthread_mutex_lock( &mutex1 );, where it looks like the mutex is being locked, when what I really want to lock is some other variable. Does this syntax mean that locking a mutex locks a region of code until the mutex is unlocked? Then how do threads know that the region is locked? [UPDATE: Threads know that the region is locked, by Memory Fencing ]. And isn't such a phenomenon supposed to be called critical section? [UPDATE: Critical section objects are available in Windows only, where the objects are faster than mutexes and are visible only to the thread which implements it. Otherwise, critical section just refers to the area of code protected by a mutex]

关于互斥锁的工作逻辑,最简单的示例程序和最简单的解释是什么?


当前回答

函数pthread_mutex_lock()要么为调用线程获取互斥量,要么阻塞线程,直到获得互斥量。相关的pthread_mutex_unlock()释放互斥量。

把互斥锁看作一个队列;每个试图获取互斥锁的线程都将被放在队列的末尾。当一个线程释放互斥锁时,队列中的下一个线程将退出并正在运行。

临界段是指代码中可能存在不确定性的区域。这通常是因为多个线程试图访问一个共享变量。在某种同步到位之前,临界区是不安全的。互斥锁是同步的一种形式。

其他回答

在使用互斥锁保护的区域之前,您应该检查互斥锁变量。因此,pthread_mutex_lock()可以(取决于实现)等待mutex1被释放,或者返回一个值,表明如果其他人已经锁定了锁,则无法获得锁。

Mutex is really just a simplified semaphore. If you read about them and understand them, you understand mutexes. There are several questions regarding mutexes and semaphores in SO. Difference between binary semaphore and mutex, When should we use mutex and when should we use semaphore and so on. The toilet example in the first link is about as good an example as one can think of. All code does is to check if the key is available and if it is, reserves it. Notice that you don't really reserve the toilet itself, but the key.

函数pthread_mutex_lock()要么为调用线程获取互斥量,要么阻塞线程,直到获得互斥量。相关的pthread_mutex_unlock()释放互斥量。

把互斥锁看作一个队列;每个试图获取互斥锁的线程都将被放在队列的末尾。当一个线程释放互斥锁时,队列中的下一个线程将退出并正在运行。

临界段是指代码中可能存在不确定性的区域。这通常是因为多个线程试图访问一个共享变量。在某种同步到位之前,临界区是不安全的。互斥锁是同步的一种形式。

以下是我向世界各地的新手解释这个概念的谦卑尝试:(在我的博客上也有一个彩色编码版本)

A lot of people run to a lone phone booth (they don't have mobile phones) to talk to their loved ones. The first person to catch the door-handle of the booth, is the one who is allowed to use the phone. He has to keep holding on to the handle of the door as long as he uses the phone, otherwise someone else will catch hold of the handle, throw him out and talk to his wife :) There's no queue system as such. When the person finishes his call, comes out of the booth and leaves the door handle, the next person to get hold of the door handle will be allowed to use the phone.

一条线索是:每个人 互斥对象是:门把手 锁是:人的手 资源为:话机

任何线程都必须执行一些不应同时被其他线程修改的代码行(使用电话与他的妻子通话),必须首先获得一个互斥锁(抓住摊位的门把手)。只有这样,线程才能运行这些代码行(进行电话调用)。

一旦线程执行了该代码,它应该释放互斥锁,以便另一个线程可以获得互斥锁(其他人可以访问电话亭)。

[当考虑到现实世界的独占访问时,拥有互斥量的概念有点荒谬,但在编程世界中,我想没有其他方法可以让其他线程“看到”一个线程已经在执行一些代码行。有递归互斥锁等概念,但这个例子只是为了向您展示基本概念。希望这个例子能让你清楚地了解这个概念。

c++ 11线程:

#include <iostream>
#include <thread>
#include <mutex>

std::mutex m;//you can use std::lock_guard if you want to be exception safe
int i = 0;

void makeACallFromPhoneBooth() 
{
    m.lock();//man gets a hold of the phone booth door and locks it. The other men wait outside
      //man happily talks to his wife from now....
      std::cout << i << " Hello Wife" << std::endl;
      i++;//no other thread can access variable i until m.unlock() is called
      //...until now, with no interruption from other men
    m.unlock();//man lets go of the door handle and unlocks the door
}

int main() 
{
    //This is the main crowd of people uninterested in making a phone call

    //man1 leaves the crowd to go to the phone booth
    std::thread man1(makeACallFromPhoneBooth);
    //Although man2 appears to start second, there's a good chance he might
    //reach the phone booth before man1
    std::thread man2(makeACallFromPhoneBooth);
    //And hey, man3 also joined the race to the booth
    std::thread man3(makeACallFromPhoneBooth);

    man1.join();//man1 finished his phone call and joins the crowd
    man2.join();//man2 finished his phone call and joins the crowd
    man3.join();//man3 finished his phone call and joins the crowd
    return 0;
}

使用g++ -std=c++0x -pthread -o thread编译并运行thread.cpp

如果您正在使用作用域锁,而不是显式地使用lock和unlock,则可以使用如下所示的括号。不过作用域锁有轻微的性能开销。

信号量示例:

sem_t m;
sem_init(&m, 0, 0); // initialize semaphore to 0

sem_wait(&m);
// critical section here
sem_post(&m);

参考资料:http://pages.cs.wisc.edu/~remzi/Classes/537/Fall2008/Notes/threads-semaphores.txt

对于那些寻找shortex互斥锁例子的人:

#include <mutex>

int main() {
    std::mutex m;

    m.lock();
    // do thread-safe stuff
    m.unlock();
}