多线程数据共享时引发的问题:
- 有两个售票窗口,两个窗口同时查询了同一次列车的余票信息,然后同时锁定同一个座位并卖出,此时,同一个座位被出售了两次。
- 生产者/消费者
一、互斥量(mutex)
可以理解成一个锁,只有锁成功才会继续向下执行,否则阻塞线程。
使用原则:只保护需要保护的信息。
- lock(), unlock()必须成对出现
#include <iostream>
#include <thread>
#include <list>
#include <mutex>
using namespace std;
class A {
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; ++i) {
cout << "push one command : " << i << endl;
my_mutex.lock();
msgRecvQueue.push_back(i);
my_mutex.unlock();
}
}
bool outMsgProc(int &command) {
my_mutex.lock();
if (!msgRecvQueue.empty()) {
//消息不为空
command = msgRecvQueue.front();
//cout << "received command is " << command << endl;
msgRecvQueue.pop_front();
my_mutex.unlock(); //解锁
return true;
}
my_mutex.unlock(); //解锁
return false;
}
void outMsgRecvQueue()
{
for (int i = 0; i < 10000; ++i) {
int command = 0;
while (!outMsgProc(command)) {
//消息队列为空
cout << "msgRecvQueue is empty" << endl;
}
cout << "received command is " << command << endl;
}
}
private:
list<int> msgRecvQueue; //容器,收到的消息
std::mutex my_mutex; //互斥量,lock()和unlock()必须成对使用
};
int main() {
A myobj;
std::thread myInMsgObj(&A::inMsgRecvQueue, &myobj);
std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobj);
myInMsgObj.join();
myOutMsgObj.join();
return 0;
}
- std::lock_guard()类模板,取代lock()和unlock(),作用就是会主动析构,不再需要unlock()
lock_guard构造函数里执行了lock(),lock_guard析构函数里执行了unlock(),所以当lock_guard对象生命周期结束,就会自行unlock()
#include <iostream>
#include <thread>
#include <list>
#include <mutex>
using namespace std;
class A {
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; ++i) {
cout << "push one command : " << i << endl;
//my_mutex.lock();
//msgRecvQueue.push_back(i);
//my_mutex.unlock();
{ //第二种写法
//{}显式声明sbguard的生命周期,出了{}sbguard会被系统自动回收,不再需要lock()和unlock()
std::lock_guard<std::mutex> sbguard(my_mutex);
msgRecvQueue.push_back(i);
}
//do else...
}
}
bool outMsgProc(int &command) {
//my_mutex.lock();
//if (!msgRecvQueue.empty()) {
// //消息不为空
// command = msgRecvQueue.front();
// //cout << "received command is " << command << endl;
// msgRecvQueue.pop_front();
// my_mutex.unlock(); //解锁
// return true;
//}
//my_mutex.unlock(); //解锁
std::lock_guard<std::mutex> sbguard(my_mutex); //lock_guard构造函数里执行了lock()
//lock_guard析构函数里执行了unlock()
if (!msgRecvQueue.empty()) {
//消息不为空
command = msgRecvQueue.front();
//cout << "received command is " << command << endl;
msgRecvQueue.pop_front();
return true;
}
return false;
}
void outMsgRecvQueue()
{
for (int i = 0; i < 10000; ++i) {
int command = 0;
while (!outMsgProc(command)) {
//消息队列为空
cout << "msgRecvQueue is empty" << endl;
}
cout << "received command is " << command << endl;
}
}
private:
list<int> msgRecvQueue; //容器,收到的消息
std::mutex my_mutex; //互斥量,lock()和unlock()必须成对使用
};
int main() {
A myobj;
std::thread myInMsgObj(&A::inMsgRecvQueue, &myobj);
std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobj);
myInMsgObj.join();
myOutMsgObj.join();
return 0;
}