1. 利用栈特性自动释放锁 RAII
1.1 什么是 RAII
1.2 手动实现 RAII 管理 mutex 资源
-
#include <iostream> #include <thread> #include <string> #include <mutex> using namespace std; // RAII class XMutex { public: // 在构造函数中锁住,一生成对象 mux 就拿到锁 XMutex(mutex &mux) : mux_(mux) { cout << "Lock" << endl; mux.lock(); } // 析构函数中释放 ~XMutex() { cout << "Unlock" << endl; mux_.unlock(); } private: // 引用方式存储锁,引用必须在初始化时就要赋值 mutex& mux_; }; static mutex mux; void TextMutex(int status) { XMutex lock(mux); // 不需要关心锁的 unlock() 释放 if (status == 1) { cout << " = 1" << endl; return; } else { cout << " != 1" << endl; return; } } // 超出这个大括号后,会调用析构函数释放栈中资源 int main(int argc, char* argv[]) { TextMutex(1); TextMutex(2); getchar(); return 0; }
-
Lock = 1 Unlock Lock != 1 Unlock
2. lock_guard:C++11 支持的 RAII 管理互斥资源
-
#include <thread> #include <iostream> #include <string> #include <mutex> using namespace std; static mutex gmutex; void TestLockGuard(int i) { gmutex.lock(); { // 已经拥有锁,不锁定,退出解锁 lock_guard<mutex> lock(gmutex, adopt_lock); // 结束释放锁 } { lock_guard<mutex> lock(gmutex); cout << "begin thread " << i << endl; } for (;;) { { lock_guard<mutex> lock(gmutex); cout << "In " << i << endl; } this_thread::sleep_for(500ms); } } int main(int argc, char* argv[]) { for (int i = 0; i < 3; i++) { thread th(TestLockGuard, i + 1); th.detach(); } getchar(); return 0; }
-
begin thread 1 In 1 begin thread 3 In 3 begin thread 2 In 2 In 1 In 2 In 3 In 1 ...
3. unique_lock:C++11 实现可移动的互斥体所有权包装器
-
支持临时释放锁 unlock
-
支持 try_to_lock:尝试获得互斥的所有权而不阻塞,获取失败退出栈区不会释放,通过 owns_lock() 函数判断
-
#include <thread> #include <iostream> #include <string> #include <mutex> using namespace std; int main(int argc, char* argv[]) { { static mutex mux; { unique_lock<mutex> lock(mux); lock.unlock(); // 临时释放锁 lock.lock(); } { // 已经拥有锁 不锁定,退出栈区解锁 mux.lock(); unique_lock<mutex> lock(mux, adopt_lock); } { // 延后加锁 不拥有 退出栈区不解锁 unique_lock<mutex> lock(mux, defer_lock); // 加锁 退出栈区解锁 lock.lock(); } { //mux.lock(); // 尝试加锁 不阻塞 失败不拥有锁 unique_lock<mutex> lock(mux, try_to_lock); if (lock.owns_lock()) { cout << "owns_lock" << endl; } else { cout << "not owns_lock" << endl; } } } getchar(); return 0; }
4. shared_lock C++14 实现可移动的共享互斥体所有权封装器
int main(int argc, char* argv[]) {
{
// 共享锁
static shared_timed_mutex tmux;
// 读取锁--共享锁
{
// 调用共享锁
shared_lock<shared_timed_mutex> lock(tmux);
cout << "read data" << endl;
// 退出栈区 释放共享锁
}
// 写入锁--互斥锁
{
unique_lock<shared_timed_mutex> lock(tmux);
cout << "write data" << endl;
}
}
}
5. 案例:使用互斥锁和 List 实现多线程通信
- 封装线程基类 XThread 控制线程启动和停止
- 模拟消息服务器线程,接收字符串消息,并模拟处理
- 通过 unique_lock 和 mutex 互斥访问 list<string> 消息队列
- 主线程定时发送消息给子线程
5.1 xthread.h
#pragma once
#include <thread>
class XThread {
public:
// 启动线程
virtual void Start();
// 设置线程退出标志 并等待
virtual void Stop();
// 等待线程退出(阻塞)
virtual void Wait();
// 线程是否退出
bool is_exit();
private:
// 线程入口
virtual void Main() = 0;
bool is_exit_ = false;
std::thread th_;
};
5.2 xthread.cpp
#include "xthread.h"
using namespace std;
// 启动线程
void XThread::Start() {
is_exit_ = false;
th_ = thread(&XThread::Main, this);
}
// 设置线程退出标志 并等待
void XThread::Stop() {
is_exit_ = true;
Wait();
}
// 等待线程退出(阻塞)
void XThread::Wait() {
if (th_.joinable())
th_.join();
}
// 线程是否退出
bool XThread::is_exit() {
return is_exit_;
}
5.3 xmsg_server.h
#pragma once
#include "xthread.h"
#include <string>
#include <list>
#include <mutex>
class XMsgServer : public XThread {
public:
// 给当前线程发消息
void SendMsg(std::string msg);
private:
// 处理消息的线程入口函数
void Main() override;
// 消息队列缓冲
std::list<std::string> msgs_;
// 互斥访问消息队列
std::mutex mux_;
};
5.4 xmsg_server.cpp
#include "xmsg_server.h"
#include <iostream>
using namespace std;
using namespace this_thread;
// 处理消息的线程入口函数
void XMsgServer::Main() {
while (!is_exit()) {
sleep_for(10ms);
unique_lock<mutex> lock(mux_);
if (msgs_.empty())
continue;
while (!msgs_.empty()) {
// 消息处理业务逻辑
cout << "recv : " << msgs_.front() << endl;
msgs_.pop_front();
}
}
}
// 给当前线程发消息
void XMsgServer::SendMsg(std::string msg) {
unique_lock<mutex> lock(mux_);
msgs_.push_back(msg);
}
5.5 thread_msg_server
#include "xmsg_server.h"
#include <sstream>
using namespace std;
int main(int argc, char* argv[]) {
XMsgServer server;
server.Start();
for (int i = 0; i < 10; i++) {
stringstream ss;
ss << " msg : " << i + 1;
server.SendMsg(ss.str());
this_thread::sleep_for(500ms);
}
server.Stop();
return 0;
}
6. 条件变量应用场景_生产者消费者信号处理步骤
6.1 改变共享变量的线程步骤
- 准备好信号量
std::condition_variable cv;
- 1、获得 std::mutex(常通过 std::unique_lock)
unique_lock lock(mux);
- 2、在获取锁时进行修改
msgs_.push_back(data);
- 3、释放锁并通知读取线程
lock.unlock(); cv.notify_one(); // 通知一个等待信号线程 cv.notify_all(); // 通知所有等待信号线程
6.2 等待信号读取共享变量的线程步骤
- 1、获得与改变共享变量线程共同的 mutex
unique_lock lock(mux);
- 2、wait() 等待信号通知
// 解锁,并阻塞等待 notify_one notify_all 通知 cv.wait(lock); // 接收到通知会再次获取锁标志,也就是说如果此时 mux 资源被占用,wait 函数会阻塞 msgs_.front(); // 处理数据 msgs_pop_front();
7. condition_variable 读写线程同步
#include <thread>
#include <iostream>
#include <mutex>
#include <list>
#include <string>
#include <sstream>
using namespace std;
list<string> msgs_;
mutex mux;
condition_variable cv;
void ThreadWrite() {
for (int i = 0;;i++) {
stringstream ss;
ss << "Write msg " << i;
unique_lock<mutex> lock(mux);
msgs_.push_back(ss.str());
lock.unlock();
cv.notify_one(); // 发送信号
//cv.notify_all();
this_thread::sleep_for(3s);
}
}
void ThreadRead(int i) {
for (;;) {
cout << "read msg" << endl;
unique_lock<mutex> lock(mux);
//cv.wait(lock); // 解锁、阻塞等待信号
cv.wait(lock, [i]
{
cout << i << " wait" << endl;
return !msgs_.empty();
});
// 获取信号后锁定
while (!msgs_.empty()) {
cout << i << " read " << msgs_.front() << endl;
msgs_.pop_front();
}
}
}
int main(int argc, char* argv[]) {
thread th(ThreadWrite);
th.detach();
for (int i = 0; i < 3; i++) {
thread th(ThreadRead, i + 1);
th.detach();
}
getchar();
return 0;
}
原文地址:https://blog.csdn.net/qq_42994487/article/details/134634570
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_22730.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。