Linux線程喚醒與等待


生產者消費者模式在程序設計中出現頻率非常高,經常會有線程間通過消息隊列或其他共享變量進行交互的場景。而這時就會出現一個問題,消費者如何知道生產者已經生產了數據呢?有的程序會采取消費者循環判斷消息隊列大小是否為0,如果不為0則取出數據之類的方法。但是該種方法帶來兩個問題:

1. 生產者產出數據到消費者獲得數據的延時較大。

2. CPU占用較高。

如果需要降低延時,則必然要提高輪詢的頻率,那么CPU占用就會升高。反之亦然,兩者無法同時解決。

於是,喚醒等待機制就成為適合該種場景的解決方案。

該機制需要一個互斥對象以及條件變量共同完成,如下:

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex;

其中條件變量使用宏結構常量進行賦值。接下來進行互斥對象與條件變量的初始化:

pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);

生產者喚醒邏輯:

pthread_mutex_lock(&mutex);  
pthread_cond_signal(&cond);   
pthread_mutex_unlock(&mutex);

消費者等待邏輯:

pthread_mutex_lock(&mutex);  
pthread_cond_wait(&cond, &mutex);  
pthread_mutex_unlock(&mutex);

看到這里可能會有點疑問,為何除了條件變量還需要一個互斥對象呢?等待時為什么需要條件變量和互斥對象共同生效呢?

條件變量的操作也需要達到線程安全的要求,因此需要互斥對象來進行保證。避免兩個線程同時操作條件變量引發問題。而通過查閱pthread_cond_wait()的相關資料可知,當程序運行到pthread_cond_wait()時,會將互斥對象鎖釋放,以便生產者能夠順利喚醒。而在消費者被成功喚醒,pthread_cond_wait()等待完成后,互斥對象會被重新上鎖直到手動釋放。

下方提供完整的DEMO以供參考:

/* test.cpp */

#include <pthread.h>
#include <iostream>
#include <signal.h>
#include <stdlib.h>  
#include <unistd.h>  

using namespace std;

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex;

void *ThreadFunc(void *arg) {  
  
  pthread_mutex_lock(&mutex);  
  /*此處等待喚醒*/
  cout << "Thread sleeping..." << endl;
  pthread_cond_wait(&cond, &mutex);  
  /*喚醒成功*/    
  cout << "Thread awakened!" << endl;
  pthread_mutex_unlock(&mutex);

  return NULL;
}

int main(void) {

  pthread_mutex_init(&mutex, NULL);
  pthread_cond_init(&cond, NULL);

  pthread_t tid;
  pthread_create(&tid, NULL, ThreadFunc, NULL);  

  /*等待5秒再喚醒,方便觀察*/
  usleep(5000000);

  pthread_mutex_lock(&mutex);  
  /*喚醒*/
  pthread_cond_signal(&cond);   
  pthread_mutex_unlock(&mutex);

  return 0;
}

附上操作命令:

g++ test.cpp -o test -pthread
./test


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM