文章目录
- mutex(互斥元)
- 案例 1
- 案例2
- lock_guard()
- 案例2的优化
由C++标准提供的保护共享数据的最基本机制是:互斥元 (mutex 全称为: mutual exclusive)
在访问共享数据前, 锁定( lock)与该数据相关的互斥元,当访问数据结构完成后, 解锁( unlock)该互斥元。线程库一旦一个线程已经锁定某个互斥元,所有其他试图锁定相同互斥元的线程都必须等待,直到成功锁定了该互斥元的线程解锁此互斥元。
互斥元是C++中最常见的数据保护机制。
在C++中,通过构造std::mutex的实例创建互斥元,调用成员函数lock()来锁定它,调用成员函数unlock()来解锁它。
mutex(互斥元)
案例 1
线程对象th1通过传入的线程函数print_block,打印50个*
。
线程对象th2通过传入的线程函数print_block,打印50个$
。
#include <iostream>
#include <mutex>
# include<thread>
using namespace std;mutex mtx; // mutex for critical sectionvoid print_block( int n, char c) {// critical section (exclusive access to std::cout signaled by locking mtx):mtx.lock();//加锁for( int i = 0; i<n; ++i) { std:: cout<< c; }std:: cout<< '\n';mtx.unlock();//释放锁
}int main(int argc, char *argv[])
{ std::thread th1(print_block, 50, '*');std::thread th2(print_block, 50, '$');th1.join();th2.join();return 0;
}
案例2
线程th1和线程th2,都通过传入的线程函数print_global_var,分别对全局变量a,进行自增20次。
#include <iostream>
#include <mutex>
#include<thread>
using namespace std;int a = 0;
void print_global_var(){for(int i=0; i<20; i++){mtx.lock();//加锁thread::id tid = this_thread::get_id();a++;cout << "tid:" << tid << " a:" << a << endl;mtx.unlock();//解锁}}
int main(int argc, char *argv[])
{ std::thread th1(print_global_var);std::thread th2(print_global_var);th1.join();th2.join();return 0;
}
critical section
: 指的是每个线程中访问临界资源的那段代码,不论是硬件临界资源,还是软件临界资源,多个线程必须互斥地对它进行访问。就是指的加锁和解锁之间的那段代码。
lock_guard()
在C++中,通过构造std::mutex的实例创建互斥元,调用成员函数lock()来锁定它,调用成员函数unlock()来解锁它。
然而,直接调用成员函数是不推荐的做法,因为这意味着你必须记住在离开函数的每条代码路径上都调用unlock(),包括由于异常所导致的在内。
作为替代,标准C++库提供了std::lock_guard类模板,实现了互斥元的RAII惯用语法;它在构造时锁定所给的互斥元
,在析构时将互斥元解锁
,从而保证被锁定的互斥元始终被正确解锁。
案例2的优化
#include <iostream>
#include <mutex>
# include<thread>
using namespace std;
mutex mtx; // mutex for critical sectionint a = 0;
void print_global_var(){for(int i=0; i<20; i++){lock_guard<mutex> guard(mtx);//在构造guard对象时锁定所给的互斥元,在析构guard对象时将互斥元解锁//mtx.lock();//加锁thread::id tid = this_thread::get_id();a++;cout << "tid:" << tid << " a:" << a << endl;//mtx.unlock();//解锁}}int main(int argc, char *argv[])
{ std::thread th1(print_global_var);std::thread th2(print_global_var);th1.join();th2.join();return 0;
}