C++多线程编程第五讲--互斥量概念、用法、死锁演示及解决详解
//(1)互斥量的(mutex)的基本概念
// 就是一个类的对象。多个线程可以尝试对一个mutex的对象进行lock,但是只有一个线程成功,其他线程需要等待。
//(2)互斥量的用法
//(2.1)lock(), unlock():要成对使用
#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
using namespace std;
class A
{
public:
//把收到的消息,入到一个队列中
void inMsgRecvQueue()
{
int i;
for (i = 0; i < 100000; ++i)
{
cout << "push_back num = " << i << endl;
//lock之后只能有一个线程可以对msgQueue队列做操作
my_mutex.lock();
msgQueue.push_back(i); //数字i就是玩家的命令。
my_mutex.unlock();
}
}
bool outMsgProc(int& command)
{
my_mutex.lock();
if (!msgQueue.empty())
{
//消息不为空
command = msgQueue.front();
msgQueue.pop_front(); //移除首元素
my_mutex.unlock();
return true;
}
else
{
my_mutex.unlock();
return false;
}
}
//把数据从消息队列中取出
void outMsgRecvQueue()
{
int i;
int command = 0;
for (i = 0; i < 100000; ++i)
{
int result = outMsgProc(command);
if (result == true)
{
cout << "command = " << command << endl;
}
else
{
cout << "msgQueue is empty" << endl;
}
}
}
private:
list<int> msgQueue;
mutex my_mutex; //创建一个互斥量
};
int main()
{
A myobj;
thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj)); //保证线程中用的同一个对象
thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));
myOutMsg.join();
myInMsg.join();
cout << "main thread end..." << endl;
return 0;
}
//(2.2)std::lock_guard类模板,与智能指针的作用是一致的,就是为了更加智能的释放资源。
#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
using namespace std;
class A
{
public:
//把收到的消息,入到一个队列中
void inMsgRecvQueue()
{
int i;
for (i = 0; i < 100000; ++i)
{
cout << "push_back num = " << i << endl;
//lock之后只能有一个线程可以对msgQueue队列做操作
lock_guard<mutex> sbguard(my_mutex);
msgQueue.push_back(i); //数字i就是玩家的命令。
}
}
bool outMsgProc(int& command)
{
lock_guard<mutex> sbguard(my_mutex);
if (!msgQueue.empty())
{
//消息不为空
command = msgQueue.front();
msgQueue.pop_front(); //移除首元素
return true;
}
else
{
return false;
}
}
//把数据从消息队列中取出
void outMsgRecvQueue()
{
int i;
int command = 0;
for (i = 0; i < 100000; ++i)
{
int result = outMsgProc(command);
if (result == true)
{
cout << "command = " << command << endl;
}
else
{
cout << "msgQueue is empty" << endl;
}
}
}
private:
list<int> msgQueue;
mutex my_mutex; //创建一个互斥量
};
int main()
{
A myobj;
thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj)); //保证线程中用的同一个对象
thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));
myOutMsg.join();
myInMsg.join();
cout << "main thread end..." << endl;
return 0;
}
//(3)死锁:必须要有两把锁,才能出现死锁。
//(3.1)死锁演示
#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
using namespace std;
class A
{
public:
//把收到的消息,入到一个队列中
void inMsgRecvQueue()
{
int i;
for (i = 0; i < 100000; ++i)
{
cout << "push_back num = " << i << endl;
//lock之后只能有一个线程可以对msgQueue队列做操作
my_mutex1.lock();
//...
my_mutex2.lock();
//...
msgQueue.push_back(i); //数字i就是玩家的命令。
//...
my_mutex2.unlock();
//...
my_mutex1.unlock();
}
}
bool outMsgProc(int& command)
{
my_mutex2.lock();
//...
my_mutex1.lock();
if (!msgQueue.empty())
{
//消息不为空
command = msgQueue.front();
msgQueue.pop_front(); //移除首元素
my_mutex1.unlock();
my_mutex2.unlock();
return true;
}
else
{
my_mutex1.unlock();
my_mutex2.unlock();
return false;
}
}
//把数据从消息队列中取出
void outMsgRecvQueue()
{
int i;
int command = 0;
for (i = 0; i < 100000; ++i)
{
int result = outMsgProc(command);
if (result == true)
{
cout << "command = " << command << endl;
}
else
{
cout << "msgQueue is empty" << endl;
}
}
}
private:
list<int> msgQueue;
mutex my_mutex1;
mutex my_mutex2;
};
int main()
{
A myobj;
thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj)); //保证线程中用的同一个对象
thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));
myOutMsg.join();
myInMsg.join();
cout << "main thread end..." << endl;
return 0;
}
//(3.2)死锁的一般解决方案:只要保证锁的lock顺序一致就不会出现死锁。
#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
using namespace std;
class A
{
public:
//把收到的消息,入到一个队列中
void inMsgRecvQueue()
{
int i;
for (i = 0; i < 100000; ++i)
{
cout << "push_back num = " << i << endl;
//lock之后只能有一个线程可以对msgQueue队列做操作
my_mutex1.lock();
//...
my_mutex2.lock();
//...
msgQueue.push_back(i); //数字i就是玩家的命令。
//...
my_mutex2.unlock();
//...
my_mutex1.unlock();
}
}
bool outMsgProc(int& command)
{
my_mutex1.lock();
//...
my_mutex2.lock();
if (!msgQueue.empty())
{
//消息不为空
command = msgQueue.front();
msgQueue.pop_front(); //移除首元素
my_mutex2.unlock();
my_mutex1.unlock();
return true;
}
else
{
my_mutex2.unlock();
my_mutex1.unlock();
return false;
}
}
//把数据从消息队列中取出
void outMsgRecvQueue()
{
int i;
int command = 0;
for (i = 0; i < 100000; ++i)
{
int result = outMsgProc(command);
if (result == true)
{
cout << "command = " << command << endl;
}
else
{
cout << "msgQueue is empty" << endl;
}
}
}
private:
list<int> msgQueue;
mutex my_mutex1;
mutex my_mutex2;
};
int main()
{
A myobj;
thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj)); //保证线程中用的同一个对象
thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));
myOutMsg.join();
myInMsg.join();
cout << "main thread end..." << endl;
return 0;
}
//(3.3)std::lock()函数模板
// 一次锁住两个或两个以上的互斥量。如果这些锁中其中有一个没有lock成功,则释放已经lock的mutex对象,
// 并在这句代码中不断的循环执行为所有的mutex对象上锁的行为,直到所有的互斥量都锁成功为止。
#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
using namespace std;
class A
{
public:
//把收到的消息,入到一个队列中
void inMsgRecvQueue()
{
int i;
for (i = 0; i < 100000; ++i)
{
cout << "push_back num = " << i << endl;
//lock之后只能有一个线程可以对msgQueue队列做操作
std::lock(my_mutex1, my_mutex2);
//...
msgQueue.push_back(i); //数字i就是玩家的命令。
//...
my_mutex2.unlock();
//...
my_mutex1.unlock();
}
}
bool outMsgProc(int& command)
{
std::lock(my_mutex1, my_mutex2);
if (!msgQueue.empty())
{
//消息不为空
command = msgQueue.front();
msgQueue.pop_front(); //移除首元素
my_mutex2.unlock();
my_mutex1.unlock();
return true;
}
else
{
my_mutex2.unlock();
my_mutex1.unlock();
return false;
}
}
//把数据从消息队列中取出
void outMsgRecvQueue()
{
int i;
int command = 0;
for (i = 0; i < 100000; ++i)
{
int result = outMsgProc(command);
if (result == true)
{
cout << "command = " << command << endl;
}
else
{
cout << "msgQueue is empty" << endl;
}
}
}
private:
list<int> msgQueue;
mutex my_mutex1;
mutex my_mutex2;
};
int main()
{
A myobj;
thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj)); //保证线程中用的同一个对象
thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));
myOutMsg.join();
myInMsg.join();
cout << "main thread end..." << endl;
return 0;
}
//(3.4)std::lock_guard的adopt_lock参数
//不必自己unlock
#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>
using namespace std;
class A
{
public:
//把收到的消息,入到一个队列中
void inMsgRecvQueue()
{
int i;
for (i = 0; i < 100000; ++i)
{
cout << "push_back num = " << i << endl;
//lock之后只能有一个线程可以对msgQueue队列做操作
std::lock(my_mutex1, my_mutex2);
lock_guard<mutex> lock_guard1(my_mutex1, std::adopt_lock);
lock_guard<mutex> lock_guard2(my_mutex2, std::adopt_lock);
//...
msgQueue.push_back(i); //数字i就是玩家的命令。
//...
}
}
bool outMsgProc(int &command)
{
std::lock(my_mutex1, my_mutex2);
lock_guard<mutex> lock_guard1(my_mutex1, std::adopt_lock);
lock_guard<mutex> lock_guard2(my_mutex2, std::adopt_lock);
if (!msgQueue.empty())
{
//消息不为空
command = msgQueue.front();
msgQueue.pop_front(); //移除首元素
return true;
}
else
{
return false;
}
}
//把数据从消息队列中取出
void outMsgRecvQueue()
{
int i;
int command = 0;
for (i = 0; i < 100000; ++i)
{
int result = outMsgProc(command);
if (result == true)
{
cout << "command = " << command << endl;
}
else
{
cout << "msgQueue is empty" << endl;
}
}
}
private:
list<int> msgQueue;
mutex my_mutex1;
mutex my_mutex2;
};
int main()
{
A myobj;
thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj)); //保证线程中用的同一个对象
thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));
myOutMsg.join();
myInMsg.join();
cout << "main thread end..." << endl;
return 0;
}
posted on 2021-10-07 18:31 xcxfury001 阅读(100) 评论(0) 收藏 举报
浙公网安备 33010602011771号