C++ 互斥示例/教程?

C++ 互斥示例/教程?,c++,c,multithreading,synchronization,mutex,C++,C,Multithreading,Synchronization,Mutex,我是多线程新手,并且试图理解互斥锁是如何工作的。做了很多谷歌搜索,但它仍然留下了一些关于它如何工作的疑问,因为我创建了自己的程序,在其中锁定不起作用 互斥体的一个绝对不直观的语法是pthread\u mutex\u lock(&mutex1),看起来互斥锁被锁定了,而我真正想锁定的是其他变量。这个语法是否意味着锁定互斥锁会锁定代码区域,直到该互斥锁被解锁?那么线程如何知道该区域已锁定?[更新:线程知道该区域已通过锁定]。这种现象不应该被称为临界区吗?[更新:Critical section对象仅

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

互斥体的一个绝对不直观的语法是
pthread\u mutex\u lock(&mutex1),看起来互斥锁被锁定了,而我真正想锁定的是其他变量。这个语法是否意味着锁定互斥锁会锁定代码区域,直到该互斥锁被解锁?那么线程如何知道该区域已锁定?[更新:线程知道该区域已通过锁定]。这种现象不应该被称为临界区吗?[更新:Critical section对象仅在Windows中可用,该对象比互斥体快,并且仅对实现它的线程可见。否则,Critical section仅指受互斥体保护的代码区域]


简而言之,请您提供最简单的互斥示例程序和最简单的解释,以了解其工作原理?我相信这会帮助很多新手。

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


互斥实际上只是一个简化的信号量。如果你阅读并理解了它们,你就理解了互斥体。SO中有几个关于互斥体和信号量的问题,等等第一个链接中的厕所示例与我们所能想到的一样好。代码所做的只是检查密钥是否可用,如果可用,则保留它。请注意,您实际上并没有保留马桶本身,而是保留钥匙。

函数
pthread\u mutex\u lock()
获取调用线程的互斥锁,或者阻塞线程,直到可以获取互斥锁为止。相关的
pthread\u mutex\u unlock()
释放互斥锁

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


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

我所知道的最好的线程教程如下:

我喜欢它是关于API的,而不是关于一个特定的实现,并且它提供了一些很好的简单示例来帮助您理解同步。

下面是我向世界各地的新手解释这个概念的拙劣尝试:(在我的博客上也是)

很多人跑到一个单独的电话亭(他们没有手机)与他们的亲人交谈。第一个抓住展台门把手的人是被允许使用电话的人。只要他使用电话,他就必须一直抓住门把手,否则其他人会抓住把手,把他扔出去,然后和他的妻子说话:)没有排队系统。当这个人打完电话,走出电话亭,离开门把手时,下一个抓住门把手的人将被允许使用电话

一条线索是:每个人
互斥锁是:门把手
锁是:人的手
资源是:电话

任何线程如果必须执行某些代码行,而这些代码行不应同时被其他线程修改(使用电话与妻子通话),则必须首先获得互斥锁(紧握展台的门把手)。只有这样,线程才能运行这些代码行(拨打电话)

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

[在考虑真实世界的独占访问时,拥有互斥对象的概念有点荒谬,但在编程世界中,我想没有其他方法可以让其他线程“看到”某个线程已经在执行某些代码行。有递归互斥对象等概念,但这个示例只是为了向您展示基本概念。Hope该示例为您提供了概念的清晰图像。]

使用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;
}
#包括
#包括
#包括
std::mutex m;//如果希望异常安全,可以使用std::lock\u-guard
int i=0;
void makeACallFromPhoneBooth()
{
m、 lock();//那个人抓住电话亭的门并锁上了。其他人在外面等着
//从现在起,男人高兴地和他的妻子交谈。。。。

STU::CUT< P>当互斥体可以用来解决其他问题时,它们存在的主要原因是提供互斥,从而解决所谓的竞争条件。当两个(或多个)线程或进程试图同时访问同一个变量时,我们有竞争条件的可能性。
//somewhere long ago, we have i declared as int
void my_concurrently_called_function()
{
  i++;
}
这个函数的内部看起来很简单。它只有一条语句。但是,一个典型的伪汇编语言等价物可能是:

load i from memory into a register
add 1 to i
store i back into memory
因为在i上执行增量操作都需要等价的汇编语言指令,所以我们说增量i是一种非atmoic操作。原子操作是一种可以在硬件上完成的操作,保证在指令执行开始后不会中断。增量i包括在3个原子指令中。在一个conc中
thread 1 load 0 into register from memory corresponding to i //register is currently 0
thread 1 add 1 to a register //register is now 1, but not memory is 0
thread 2 load 0 into register from memory corresponding to i
thread 2 add 1 to a register //register is now 1, but not memory is 0
thread 1 write register to memory //memory is now 1
thread 2 write register to memory //memory is now 1
#include <condition_variable>
#include <mutex>
#include <algorithm>
#include <thread>
#include <queue>
#include <chrono>
#include <iostream>


int _tmain(int argc, _TCHAR* argv[])
{   
    // these vars are shared among the following threads
    std::queue<unsigned int>    nNumbers;

    std::mutex                  mtxQueue;
    std::condition_variable     cvQueue;
    bool                        m_bQueueLocked = false;

    std::mutex                  mtxQuit;
    std::condition_variable     cvQuit;
    bool                        m_bQuit = false;


    std::thread thrQuit(
        [&]()
        {
            using namespace std;            

            this_thread::sleep_for(chrono::seconds(5));

            // set event by setting the bool variable to true
            // then notifying via the condition variable
            m_bQuit = true;
            cvQuit.notify_all();
        }
    );


    std::thread thrProducer(
        [&]()
        {
            using namespace std;

            int nNum = 13;
            unique_lock<mutex> lock( mtxQuit );

            while ( ! m_bQuit )
            {
                while( cvQuit.wait_for( lock, chrono::milliseconds(75) ) == cv_status::timeout )
                {
                    nNum = nNum + 13 / 2;

                    unique_lock<mutex> qLock(mtxQueue);
                    cout << "Produced: " << nNum << "\n";
                    nNumbers.push( nNum );
                }
            }
        }   
    );

    std::thread thrConsumer(
        [&]()
        {
            using namespace std;
            unique_lock<mutex> lock(mtxQuit);

            while( cvQuit.wait_for(lock, chrono::milliseconds(150)) == cv_status::timeout )
            {
                unique_lock<mutex> qLock(mtxQueue);
                if( nNumbers.size() > 0 )
                {
                    cout << "Consumed: " << nNumbers.front() << "\n";
                    nNumbers.pop();
                }               
            }
        }
    );

    thrQuit.join();
    thrProducer.join();
    thrConsumer.join();

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

sem_wait(&m);
// critical section here
sem_post(&m);
#include <mutex>

int main() {
    std::mutex m;

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