C/C++ 執行緒安全佇列
阿新 • • 發佈:2019-01-11
一、簡介
執行緒安全是一個比較嚴肅的問題,如果處理不好,可能導致資料被破壞,程式崩潰等問題,如何來處理多執行緒的併發問題?在windows平臺有相應的api給你用於控制併發,如互斥鎖,訊號量,事件,臨界區等,定要熟練掌握,當然現在STL庫已強大到相容不同的硬體系統了,當然對於winApi同步可以看這裡:
互斥鎖,訊號量,事件,臨界區詳情
二、分析安全原理
基於conditon_variable類實現執行緒安全,先來看看它有什麼API使
wait阻塞自己,等待喚醒
wait_for阻塞自己,等待喚醒,最多等待一段時間
wait_until阻塞自己,等待喚醒,最多等待到某個時間點
notify_one 喚醒一個等待在這個條件變數上的執行緒
notify_all 喚醒所有等待在這個條件變數上的執行緒
這個有點類似的於event,想讓某處導通就直接setEvent,
某博主的關於condition_variable比較詳細的講解:點此
三、上佇列程式碼
template<typename T> class ThreadSafe_Queue
{
private:
mutable mutex m_mut;
queue<T> m_queue;
condition_variable m_data_cond;
public:
ThreadSafe_Queue() {}
ThreadSafe_Queue(const ThreadSafe_Queue&) = delete ;
void push(T data)
{
lock_guard<mutex> lg(m_mut);
m_queue.push(data);
m_data_cond.notify_one();
}
void WaitPop(T&t)
{
unique_lock<mutex> ul(m_mut);
m_data_cond.wait(ul, [this] {return !m_queue.empty(); });
t = m_queue.front();
m_queue.pop();
}
shared_ptr <T> WaitPop()
{
unique_lock<mutex> ul(m_mut);
m_data_cond.wait(ul, [this] {return !m_queue.empty(); });
shared_ptr<T> res(make_shared<T>(m_queue.front()));
m_queue.pop();
return res;
}
bool TryPop(T &t)
{
lock_guard<mutex> lg(m_mut);
if (m_queue.empty())
return false;
t = m_queue.front();
m_queue.pop();
return true;
}
shared_ptr<T> TryPop()
{
lock_guard<mutex> lg(m_mut);
if (m_queue.empty())
return shared_ptr<T>();
shared_ptr<T> res(make_shared<T>(m_queue.front()));
m_queue.pop();
return res;
}
bool IsEmpty()
{
lock_guard<mutex> lg(m_mut);
return m_queue.empty();
}
};
四、一個小例子
開了兩個執行緒,用於測試執行緒佇列是否安全,thread_Fuc2用於插入資料,thread_Fuc用於出隊操作,經過測試,達到了安全。
ThreadSafe_Queue<int> g_queue;
int g_index = 10;
void thread_Fuc()
{
cout << "thread_fuc1 start\n";
while (true)
{
int value=0;
g_queue.WaitPop(value);
printf("wait_and_pop done! value=%d thread id:%d\n",value,GetCurrentThreadId());
}
}
void thread_Fuc2()
{
cout << "thread_fuc2 start\n";
while (true)
{
Sleep(1000);
g_index++;
g_queue.push(g_index);
}
}
int main()
{
thread thd(thread_Fuc);
thd.detach();
thread thd2(thread_Fuc2);
thd2.detach();
int a;
while (cin >> a){;}
return 0;
}
測試圖: