Data 2018/11/13 Add By WJB
在客户端显示服务发送的数据时,一般处理方法:首先创建一个deque作为缓存,接受的服务端push进deque中,客户端有一个线程取deque中数据,如图所示。
简单的处理代码如下:
mutex m_mutex;
deque<int> g_deque1;
void Function_1()
{
int count = 10;
while (count>0)
{
unique_lock<mutex> locker(m_mutex);
g_deque1.push_front(count);
locker.unlock();
this_thread::sleep_for(chrono::milliseconds(1000));
count--;
}
}
int i = 0;
void Function_2()
{
int data = 0;
while (data!=1)
{
i++;
cout << "while times" << i << endl;
unique_lock<mutex> locker(m_mutex);
if (!g_deque1.empty())
{
data = g_deque1.back();
g_deque1.pop_back();
locker.unlock();
cout << "t2 got a value form t1:" << data << endl;
}
else
{
locker.unlock();
}
}
}
int main()
{
thread thread1(Function_1);
thread thread2(Function_2);
thread1.join();
thread2.join();
return 0;
}
线程1不断写入,线程2判断队列部位空时取出一个数据。但是这样写有个问题,如果有一段时间队列为空,那么线程2就一直在无限循环,上述代码输出结果如下:
根据数据结果,很明显可以看出,在队列没有数据的时间,线程2在不段的循环,这样势必会抢占一下资源。对上述代码稍作修改,比如让线程2在判断队列为空时休眠一下,取50毫秒,这样就可以减少循环。修改后代码和输出结果如下:
int i = 0;
void Function_2()
{
int data = 0;
while (data!=1)
{
i++;
cout << "while times" << i << endl;
unique_lock<mutex> locker(m_mutex);
if (!g_deque1.empty())
{
data = g_deque1.back();
g_deque1.pop_back();
locker.unlock();
cout << "t2 got a value form t1:" << data << endl;
}
else
{
locker.unlock();
this_thread::sleep_for(chrono::milliseconds(50));
}
}
}
根据输出结果可以看出,线程2减少了很多无用的循环,但是在实际工作中,队列接受数据时间没有规律,因此线程2设置休眠的时间也很难控制, 为了解决这个问题引入条件变量condition_variable.修改代码如和输出结果如果:
头文件#include <condition_variable>
说明变量 condition_variable contion;
void Function_1()
{
int count = 10;
while (count > 0)
{
unique_lock<mutex> locker(m_mutex);
g_deque1.push_front(count);
locker.unlock();
contion.notify_one();//解锁一个等待该线程的线程
this_thread::sleep_for(chrono::milliseconds(1000));
count--;
}
}
int i = 0;
void Function_2()
{
int data = 0;
while (data != 1)
{
i++;
cout << "while times" << i << endl;
unique_lock<mutex> locker(m_mutex);
contion.wait(locker);
data = g_deque1.back();
g_deque1.pop_back();
locker.unlock();
cout << "t2 got a value form t1:" << data << endl;
}
}
结果很明显线程2没有一次多余的循环,contion.notify_one();//解锁一个等待该线程的线程,如果有多个线程等待则需要“contion.notify_all();”,为了防止线程2伪激活,需要对contion.wait()中添加一个lamda表达式参数,contion.wait(locker, [](){return !g_deque1.empty();});
最终代码如下:
#include <thread>
#include <iostream>
#include <string>
#include <deque>
#include <mutex>
#include <fstream>
#include <condition_variable>
using namespace std;
mutex m_mutex;
deque<int> g_deque1;
condition_variable contion;
void Function_1()
{
int count = 10;
while (count > 0)
{
unique_lock<mutex> locker(m_mutex);
g_deque1.push_front(count);
locker.unlock();
contion.notify_all();//解锁一个等待该线程的线程
this_thread::sleep_for(chrono::milliseconds(1000));
count--;
}
}
int i = 0;
void Function_2()
{
int data = 0;
while (data != 1)
{
i++;
cout << "while times" << i << endl;
unique_lock<mutex> locker(m_mutex);
contion.wait(locker, [](){return !g_deque1.empty();});
data = g_deque1.back();
g_deque1.pop_back();
locker.unlock();
cout << "t2 got a value form t1:" << data << endl;
}
}
int main()
{
thread thread1(Function_1);
thread thread2(Function_2);
thread1.join();
thread2.join();
return 0;
}