C++11各种锁的具体使用

news/2025/2/16 5:31:33/

1.什么是互斥量(锁)?

互斥量在实际开发中很常用,需要学习了解!
这样比喻:单位上有一台打印机(共享数据a),你要用打印机(线程1要操作数据a),同事老王也要用打印机(线程2也要操作数据a),但是打印机同一时间只能给一个人用,此时,规定不管是谁,在用打印机之前都要向领导申请许可证(lock),用完后再向领导归还许可证(unlock),许可证总共只有一个,没有许可证的人就等着在用打印机的同事用完后才能申请许可证(阻塞,线程1lock互斥量后其他线程就无法lock,只能等线程1unlock后,其他线程才能lock)。那么,打印机就是共享数据,访问打印机的这段代码就是临界区,这个必须互斥使用的许可证就是互斥量(锁)。

互斥量是为了解决数据共享过程中可能存在的访问冲突的问题。这里的互斥量保证了使用打印机这一过程不被打断。

2.死锁

死锁在实际开发中会遇到,需要学习了解!
多线程编程时要考虑多个线程同时访问共享资源所造成的问题,因此可以通过加锁解锁来保证同一时刻只有一个线程能访问共享资源;使用锁的时候要注意,不能出现死锁的状况;

死锁就是多个线程争夺共享资源导致每个线程都不能取得自己所需的全部资源,从而程序无法向下执行。

3.例子代码

对于不同线程访问统一资源时,为了避免冲突一般都通过对目标共享变量上锁和解锁,让共享变量互斥。

3.1 第一种方式:一般情况可以在共享变量前后分别上锁解锁,至少需要以下三个操作:

// 定义锁
std::mutex m_mutex;// 上锁
m_mutex.lock();// 上锁和解锁之间为对共享变量的访问操作.....// 解锁
m_mutex.unlock();

3.2 第二种方式:使用std::lock_guard,在std::lock_guard对象的作用域内进行互斥量的操作,例如:

// std::lock_guard<std::mutex>  l(s_mutex);#include <iostream>
#include <mutex>
#include <thread>
#include <windows.h>//全局变量,两个线程都会访问
int g_num = 0;
//定义锁
std::mutex m_mutex;void bar()
{//函数bar()范围内,自动为互斥量上锁和解锁std::lock_guard<std::mutex> l(m_mutex);std::cout << "This thread id is : " << std::this_thread::get_id() << "  --  g_num : " << g_num << std::endl;g_num++;
}void foo()
{while (1) {bar();Sleep(1000);}
}int main()
{std::thread first(foo);     // thread firststd::thread second(foo);    // thread secondfirst.join();               // pauses until first finishessecond.join();              // pauses until second finishesreturn 0;
}

std::lock_guard需要在作用域范围开头定义,也可以通过块操作限制其作用域范围,例如:

void func()
{....{	// 范围起始std::lock_guard<std::mutex> l(m_mutex);}	// 范围结束....
}

4.参考例子

#include "lock_guard.hpp"
#include <iostream>
#include <thread>
#include <mutex>
#include <stdexcept>
#include <list>
#include <algorithm>namespace lock_guard_ {///
// reference: http://www.cplusplus.com/reference/mutex/lock_guard/
namespace {
std::mutex mtx;void print_even(int x) {if (x % 2 == 0) std::cout << x << " is even\n";else throw (std::logic_error("not even"));
}void print_thread_id(int id) {try {// using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:std::lock_guard<std::mutex> lck(mtx);print_even(id);} catch (std::logic_error&) {std::cout << "[exception caught]\n";}
}
}int test_lock_guard_1()
{std::thread threads[10];// spawn 10 threads:for (int i = 0; i<10; ++i)threads[i] = std::thread(print_thread_id, i + 1);for (auto& th : threads) th.join();return 0;
}///
// reference: http://www.cplusplus.com/reference/mutex/lock_guard/lock_guard/
namespace {
std::mutex mtx2;           // mutex for critical sectionvoid print_thread_id2(int id) {mtx2.lock();std::lock_guard<std::mutex> lck(mtx2, std::adopt_lock);std::cout << "thread #" << id << '\n';
}
}int test_lock_guard_2()
{std::thread threads[10];// spawn 10 threads:for (int i = 0; i<10; ++i)threads[i] = std::thread(print_thread_id2, i + 1);for (auto& th : threads) th.join();return 0;
}// reference: http://en.cppreference.com/w/cpp/thread/lock_guard
namespace {
int g_i = 0;
std::mutex g_i_mutex;  // protects g_ivoid safe_increment()
{std::lock_guard<std::mutex> lock(g_i_mutex);++g_i;std::cout << std::this_thread::get_id() << ": " << g_i << '\n';// g_i_mutex is automatically released when lock goes out of scope
}
}int test_lock_guard_3()
{std::cout << "main: " << g_i << '\n';std::thread t1(safe_increment);std::thread t2(safe_increment);t1.join();t2.join();std::cout << "main: " << g_i << '\n';return 0;
}//
// reference: http://www.bogotobogo.com/cplusplus/C11/7_C11_Thread_Sharing_Memory.php
namespace {
// a global variable
std::list<int> myList;// a global instance of std::mutex to protect global variable
std::mutex myMutex;void addToList(int max, int interval)
{// the access to this function is mutually exclusivestd::lock_guard<std::mutex> guard(myMutex);for (int i = 0; i < max; i++) {if ((i % interval) == 0) myList.push_back(i);}
}void printList()
{// the access to this function is mutually exclusivestd::lock_guard<std::mutex> guard(myMutex);for (auto itr = myList.begin(), end_itr = myList.end(); itr != end_itr; ++itr) {std::cout << *itr << ",";}
}
}
int test_lock_guard_4()
{int max = 100;std::thread t1(addToList, max, 1);std::thread t2(addToList, max, 10);std::thread t3(printList);t1.join();t2.join();t3.join();return 0;
}} // namespace lock_guard_

http://www.ppmy.cn/news/1137880.html

相关文章

项目设计:YOLOv5目标检测+机构光相机(intel d455和d435i)测距

1.介绍 1.1 Intel D455 Intel D455 是一款基于结构光&#xff08;Structured Light&#xff09;技术的深度相机。 与ToF相机不同&#xff0c;结构光相机使用另一种方法来获取物体的深度信息。它通过投射可视光谱中的红外结构光图案&#xff0c;然后从被拍摄物体表面反射回来…

packihx: aborting after 3 lines.

packihx: aborting after 3 lines.

数据结构:二叉树(超详解析)

目录​​​​​​​ 1.树概念及结构 1.1树的概念 1.2树的相关概念 1.3树的表示 1.3.1孩子兄弟表示法&#xff1a; 1.3.2双亲表示法&#xff1a;只存储双亲的下标或指针 两节点不在同一树上&#xff1a; 2.二叉树概念及结构 2.1.概念 2.2.特殊的二叉树&#xff1a; 2…

php实战案例记录(15)获取GET和POST请求参数

在PHP中&#xff0c;可以使用$_GET和$_POST超全局变量来获取GET和POST请求参数。 获取GET请求参数&#xff1a; 要获取GET请求参数&#xff0c;可以使用$_GET超全局变量。它是一个关联数组&#xff0c;其中键是参数的名称&#xff0c;值是参数的值。例如&#xff0c;如果URL是…

【Java每日一题】— —第二十二题:类名作参数进行方法调用的传递问题。(2023.10.06)

&#x1f578;️Hollow&#xff0c;各位小伙伴&#xff0c;今天我们要做的是第二十二题。 &#x1f3af;问题&#xff1a; 类名作参数进行方法调用的传递问题。 形式参数的问题&#xff1a; &#xff08;1&#xff09;基本类型&#xff1a;形式参数的改变不影响实际参数。实参应…

蓝桥等考Python组别十三级003

第一部分:选择题 1、Python L13 (15分) 运行下面程序,输出的结果是( )。 t = (1, 2, 2, 1, 4, 3, 2) print(t.count(2)) 1234正确答案:C 2、Python L13 (

​“债务飙升!美国一天内增加2750亿美元,金融震荡的前奏已拉开帷幕!”

2023年10月4日&#xff0c;美国政府向美国债务追加2750亿美元&#xff0c;相当于现在比特币&#xff08;BTC&#xff09;总市值的一半还多。 有人会说:多一点、少一点&#xff0c;没什么区别.....确实&#xff0c;当你看美国债务时&#xff0c;2750亿美元并没有什么意义&#x…

数据结构刷题训练——二叉树篇(一)

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…