这篇文章主要说说线程同步的条件变量和互斥锁在线程中结合的使用,先看看几个概念
条件变量:是一种线程同步机制,条件变量允许线程睡眠,直到满足条件,当满足条件时,可以向该线程发信号,通知唤醒。
互斥锁: 互斥锁用于控制多个线程对他们之间共享资源互斥访问的一个信号量。也就是说是为了避免多个线程在某一时刻同时操作一个共享资源。
std::condition_variable 是为了解决死锁而生的。当互斥操作不够用而引入的。比如,线程可能需要等待某个条件为真才能继续执行,而一个忙等待循环中可能会导致所有其他线程都无法进入临界区使得条件为真时,就会发生死锁。所以,condition_variable实例被创建出现主要就是用于唤醒等待线程从而避免死锁。std::condition_variable的 notify_one()用于唤醒一个线程;notify_all() 则是通知所有线程。
C++11中的std::condition_variable就像Linux下使用pthread_cond_wait和pthread_cond_signal一样,可以让线程休眠,直到别唤醒,现在在从新执行。线程等待在多线程编程中使用非常频繁,经常需要等待一些异步执行的条件的返回结果。
为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起;通常情况下这个锁是std::mutex,并且管理这个锁 只能是 std::unique_lock<std::mutex>
RAII模板类。
条件满足一般使用
等待条件成立使用的是condition_variable类成员wait 、wait_for 或 wait_until。给出信号使用的是condition_variable类成员notify_one或者notify_all函数
在条件变量中只能使用std::unique_lockstd::mutex说明
unique_lock和lock_guard都是管理锁的辅助类工具,都是RAII风格;它们是在定义时获得锁,在析构时释放锁。它们的主要区别在于unique_lock锁机制更加灵活,可以再需要的时候进行lock或者unlock调用,不非得是析构或者构造时。它们的区别可以通过成员函数就可以一目了然。
在线程被阻塞时,该函数会自动调用 lck.unlock() 释放锁,使得其他被阻塞在锁竞争上的线程得以继续执行。另外,一旦当前线程获得通知(notified,通常是另外某个线程调用 notify_* 唤醒了当前线程),wait() 函数也是自动调用 lck.lock(),使得 lck 的状态和 wait 函数被调用时相同。
//代码:
std::mutex m_utex;
std::queue<int> m_queue;
std::condition_variable m_cv;
BOOL bwhile = TRUE;
void thread_read2(CMFCApplication7Dlg *pDlg)
{
while (bwhile)
{
std::unique_lock<std::mutex> m_lock(m_utex);
m_cv.wait(m_lock, [](){return !m_queue.empty(); });
if (bwhile == 0)
{
break;
}
int n = m_queue.front();
m_queue.pop();
m_lock.unlock();
CString strTmp = _T("");
strTmp.Format("thread_read2:%d", n);
SetDlgItemText(pDlg->m_hWnd, IDC_EDIT1, strTmp);
strTmp.Format("%d", m_queue.size());
SetDlgItemText(pDlg->m_hWnd, IDC_EDIT2, strTmp);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return;
}
//开启读线程
void CMFCApplication7Dlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
std::thread m_thread2(thread_read2, this);
m_thread2.detach();
GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
}
//写数据
int icount = 1;
void CMFCApplication7Dlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
m_queue.push(icount++);
m_cv.notify_one();
}