Linux Qt使用POSIX多线程条件变量、互斥锁(量)
今天團建,但是文章也要寫。酒要喝好,文要寫美,方為我輩程序員的全才之路。嘎嘎
?
之前一直在看POSIX的多線程編程,上個周末結合自己的理解,寫了一個基于Qt的用條件變量同步線程的例子。故此來和大家一起分享,希望和大家一起交流。
?
提到線程,如果在UI編程中,總會和一些耗時操作聯系在一起。Qt中處理耗時操作通常有兩種方式,一種是將耗時操作放在線程中;另一種則是使用QApplication::processEvents(),防止阻塞UI。從更加通用的角度來講,我是更傾向于線程的,但對于很多初學者來講,線程還是有一定難度的。比如說需要對線程間共享的數據提供保護,使用互斥量同步、使用條件變量、使用讀寫鎖同步等;各種同步方式用在什么情況下,開始編程時多線程使用的并不多,無法切身體會到這些問題,后來程序寫的多了一點兒,慢慢接觸到一些多線程的東西,并且自己也可以學習了相關知識,并用到實際程序中。好了,下面以一個實際的例子為背景,來說明Linux POSIX多線程的一些特性。
?
程序環境:ubuntu 14.04、 Qt 5.5.1、 Posix多線程(C的用法)
這里簡單說下我為什么用Linux C的多線程,因為Qt的多線程編程對于一些線程的終止時含糊不清楚的,并且一個線程被終止后的資源是無法被清理的,所以我選擇是相對底層的一些用法,以后有機會我還會添加線程取消和線程退出的操作。
?
我自己設定的場景是這樣的,在UI主線程中通過界面手動向一個線程間共享的隊列中push數據,而另外開啟的一個線程則一直在while中pop數據,這算是一個變種的生產者和消費者模式吧。
至于條件變量、互斥量(也就是互斥鎖)的初始化在這里不再詳細說明,只說明一些相對重要的地方。
?
1.?UI中向隊列push數據(生產者生產數)
這是一個槽函數,當在lineEdit中回車后,則會觸發該槽函數,由于該隊列是線程間的共享數據,所以使用了互斥鎖進行保護,即該槽操作數據的過程中如果有其他線程想要操作數據,則其他線程則會被阻塞,即訪問一個已經被加鎖的互斥量的線程會被阻塞。
void Widget::on_le_writeNum_returnPressed(){ int status;status = pthread_mutex_lock (&mp_processThread->m_structCondition.mutex); if (status != 0) err_abort (status, "Lock mutex");
QString num = ui->le_writeNum->text(); mp_processThread->queuePushData(num.toInt());
status = pthread_cond_signal (&mp_processThread->m_structCondition.cond);// status = pthread_cond_broadcast( &mp_processThread->m_structCondition.cond); if (status != 0) err_abort (status, "Signal condition");
status = pthread_mutex_unlock (&mp_processThread->m_structCondition.mutex); if (status != 0) err_abort (status, "Unlock mutex");}
2.?消費者線程pop數據
該線程使用的是Qt的moveToThread方法創建的線程,這里注意的是,整個類都運行在新的線程中。該槽函數隨著線程的啟動信號(start())發射后而一直進行while循環。首先對互斥量上鎖,之后判斷謂詞狀態,如果隊列為空,則等待條件變量。等待條件變量時pthread_cond_wait()會自動釋放互斥鎖,這樣其他線程才能夠操作共享數據。從條件變量等待中醒來后,會再次獲得互斥鎖,以操作共享數據。共享數據被操作完成后,再次釋放互斥鎖。這是我們使用條件變量等待的一個操作流程,如果我們不使用條件變量等待會是怎樣的呢?
void ProcessThread::slot_processData(){ int status;while(!mb_stopThread) { status = pthread_mutex_lock (&m_structCondition.mutex); if (status != 0) err_abort (status, "Lock mutex");
while(m_queue.empty()) //if queue is empty, wait contion {//使用條件變量等待 status = pthread_cond_wait(&m_structCondition.cond, &m_structCondition.mutex); // qDebug() << "pthread_cond_wait is block func!";
if (status != 0) { err_abort (status, "Wait on cond faild"); } }
while(!m_queue.empty()) { qDebug() << "queue mem is" << m_queue.back();
m_queue.pop(); }
status = pthread_mutex_unlock (&m_structCondition.mutex); if (status != 0) err_abort (status, "Unlock mutex");
}
}
3.?不使用條件變量等待
①不使用條件變量等待
如果不使用條件變量等待,則消費者線程在很大一部時間內幾乎都是在執行while(1)無限循環,這是很占用CPU資源的,在ubuntu下,使用htop查看的效果如下:
屏蔽status = pthread_cond_wait(&m_structCondition.cond,
&m_structCondition.mutex);
我們看到,此時CPU是滿負荷在運行的,這當然不是一個程序所應有的正常狀態。
②使用條件變量的結果
此時我們看到CPU的占用率是很低的,這也是為什么使用條件變量的原因之一,讓不滿足的條件的線程掛起,而不是在浪費CPU資源。條件變量是 允許使用隊列的線程之間交換隊列狀態信息的機制。那么當我們還沒有掌握線程條件變量的用法時,又遇到這種情況時,該怎么做呢?簡單,加個5ms的延時即可,5ms對我們來講時間極短極短,但對計算機來講,已經挺長時間了。
?
最后,當我們關掉UI窗口時,會有這樣一句消息:
QThread: Destroyed while thread is still running
線程正在運行時就被破壞了,這個我們接下來會說,那就是如何退出線程、終止線程以及取消線程等操作了。
歡迎大家關注公眾號一起交流!
如果需要整個工程源碼,歡迎后臺留言哦~
如果轉載,請注明出處,禁止商業用途,感謝合作。
總結
以上是生活随笔為你收集整理的Linux Qt使用POSIX多线程条件变量、互斥锁(量)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机械硬盘真没人买 已死?!希捷业绩暴跌
- 下一篇: Linux/C/C++ 不可错过的好书