POSIX執行緒程式設計起步(2)-執行緒同步 (轉)

gugu99發表於2007-08-16
POSIX執行緒程式設計起步(2)-執行緒同步 (轉)[@more@]

2.執行緒同步

POSIX提供了兩種用於執行緒同步的原語,這兩種操作分別是互斥以及條件變數。互斥是一種簡單的進行鎖定的原語,其主要作用是控制對共享資源的訪問,防止衝突。關於多執行緒,有一點值得大家注意,那就是整個的地址空間有所有的執行緒共享。其結果是幾乎所有的資源都可以被共享——比如全域性變數、描述符等。另一方面,在每個執行緒的入口(由pthread_create)內,以及由該函式呼叫的其他函式內,我們都會定義一些私有的區域性變數。在多執行緒程式中,全域性變數與區域性變數總是被混合使用,要想使多執行緒程式順利的執行,各執行緒對共享資源的訪問必須得到控制。

以下是一個生產者/消費者程式。生產者與消費者對共享緩衝區的訪問由互斥進行控制。
  void * reader_function(void *);
  void * writer_function(void *);
 
  char buffer;
  int buffer_has_item = 0;
  pthread_mutex_t mutex;
  struct timespec delay;
 
  main()
  {
  pthread_t reader;
 
  delay.tv_sec = 2;
  delay.tv_nsec = 0;
 
  pthread_mutex_init(&mutex, pthread_mutexattr_default);
  pthread_create( &reader, pthread_attr_default, reader_function,
  NULL);
  writer_function();
  }
 
  void * writer_function(void *)
  {
  while(1)
  {
  pthread_mutex_lock( &mutex );
  if ( buffer_has_item == 0 )
  {
  buffer = make_new_item();
  buffer_has_item = 1;
  }
  pthread_mutex_unlock( &mutex );
  pthread_delay_np( &delay );
  }
  }
 
  void * reader_function(void *)
  {
  while(1)
  {
  pthread_mutex_lock( &mutex );
  if ( buffer_has_item == 1)
  {
  consume_item( buffer );
  buffer_has_item = 0;
  }
  pthread_mutex_unlock( &mutex );
  pthread_delay_np( &delay );
  }
  }

上邊這個簡單的例子程式中,共享緩衝區只能儲存一個共享資料項。因此該緩衝區只有兩個狀態:“有”/“無”。生產者在向緩衝區寫入資料前,首先會將互斥上鎖,如果該互斥已被鎖定,則生產者將阻塞直到互斥被解鎖。生產者鎖定了互斥以後,將會檢查緩衝區是否為空(透過標誌變數buffer_has_item)。如果緩衝區沒有資料,生產者就會產生新資料項放入緩衝區,並設定標誌變數以使得消費者可以知道是否能進行消費。接下來生產者解除對互斥的鎖定並等待,這樣消費者應該有充足的時間來訪問緩衝區。

消費者採取了相似的過程來訪問緩衝區。它首先鎖定互斥,檢查標誌變數,如果可能則消費掉僅有的資料項。接著消費者解鎖互斥並等待一小會兒好讓生產者有時間寫入新的資料項。

上例中,生產者和消費者將會持續不斷的執行,不斷的生產、消費。事實上,在通常的程式中,如果確定不再使用某個互斥,則應該用pthread_mutex_destroy(&mutex)將其摧毀。順便提一句,在使用某個互斥之前,應該使用pthread_mutex_init()將其初始化。在我們的例子中,初始化時使用了兩個引數,第一個用來指定被初始化的互斥,第二個則是該互斥的屬性。(在DEC O/1上,互斥的屬性沒有實際意義,通常使用PTHREAD_MUTEXATTR_DEFAULT)

對互斥的正確使用可以有效地減少競爭條件。其實互斥本身是非常簡單的,只有兩個狀態:鎖定、未鎖定。它能實現的功能也是有限的。POSIX還提供了條件變數這一有力工具來補充互斥的不足。使用條件變數,一個執行緒可以在已經鎖定互斥的情況下被阻塞並等待喚醒訊號,而其他執行緒仍能訪問被鎖定的共享資源。當另外的某一個執行緒發出訊號後,被阻塞的執行緒將被喚醒並依然可以訪問阻塞前自己鎖定的共享資源。由此,互斥和條件變數的聯合使用可以幫助我們避免迴圈死鎖的情況出現。我們利用互斥和條件變數設計了一個僅有單一整數訊號燈的庫。庫的可以在附錄A中找到,關於條件變數的說明可以在手冊頁(man pages)裡找到

本節涉及的函式:
 pthread_mutex_init(), pthread_mutex_lock(),
 pthread_mutex_unlock(), and pthread_mutex_destroy().


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-960949/,如需轉載,請註明出處,否則將追究法律責任。

相關文章