Linux 條件變量 pthread_cond_signal及pthread_cond_wait

#include<pthread.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;/*靜態初始化*/
pthread_cond_t  cond = PTHREAD_COND_INITIALIZER;  //init cond

void *thread1(void*);
void *thread2(void*);
int i = 1; //global

int main(int argc,char*  argv[])
{
    pthread_t t_a;
    pthread_t t_b;//two thread

        pthread_create(&t_b,NULL,thread2,(void*)NULL);//Create thread
    pthread_create(&t_a,NULL,thread1,(void*)NULL);

    pthread_join(t_b,NULL);//wait a_b thread end
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    exit(0);
}
//t_a  實現線程t_b打印9之內3的倍數
void *thread1(void *junk){
    for(i = 1;i<= 9; i++){
        pthread_mutex_lock(&mutex); //互斥鎖
        printf("call thread1 \n");
        if(i%3 == 0)
            pthread_cond_signal(&cond); //send sianal to t_b
        else
            printf("thread1: %d\n",i);
        pthread_mutex_unlock(&mutex);
        printf("1  [%d]\n",i);
        sleep(1);
    }
}
//t-b  打印其餘的數   
void *thread2(void*junk){
    while(i < 9)
    {
        pthread_mutex_lock(&mutex);//開始進入臨界區
        printf("call thread2 \n");
        if(i%3 != 0)//操做有2步,是原子操做。第一解鎖,先解除以前的pthread_mutex_lock鎖定的mutex;第二 掛起,阻塞並在等待隊列裏休眠,即所在線程掛起,直到再次被再次喚醒,喚醒的條件是由pthread_cond_signal(&cond);發出的cond信號來喚醒。
            pthread_cond_wait(&cond,&mutex); //wait 必須和互斥鎖同時用在一個線程裏,它同時起到對資源的加鎖和解鎖
        printf("thread2: %d\n",i);
        pthread_mutex_unlock(&mutex);//離開臨界區
        printf("2 ....\n"  );
        sleep(1);
    }
ide

}this

*********************************************************************spa

int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)操作系統

pthread_cond_wait 源碼線程

{
  volatile pthread_descr self = thread_self();
  pthread_extricate_if extr;
  int already_canceled = 0;
  int spurious_wakeup_count;

  /* Check whether the mutex is locked and owned by this thread.  */
  if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
      && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
      && mutex->__m_owner != self)
    return EINVAL;

  /* Set up extrication interface */
  extr.pu_object = cond;
  extr.pu_extricate_func = cond_extricate_func;

  /* Register extrication interface */
  THREAD_SETMEM(self, p_condvar_avail, 0);
  __pthread_set_own_extricate_if(self, &extr);

  /* Atomically enqueue thread for waiting, but only if it is not
     canceled. If the thread is canceled, then it will fall through the
     suspend call below, and then call pthread_exit without
     having to worry about whether it is still on the condition variable queue.
     This depends on pthread_cancel setting p_canceled before calling the
     extricate function. */

  __pthread_lock(&cond->__c_lock, self);
  if (!(THREAD_GETMEM(self, p_canceled)
      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
    enqueue(&cond->__c_waiting, self);
  else
    already_canceled = 1;
  __pthread_unlock(&cond->__c_lock);

  if (already_canceled) {
    __pthread_set_own_extricate_if(self, 0);
    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  }

  pthread_mutex_unlock(mutex);

  spurious_wakeup_count = 0;
  while (1)
    {
      suspend(self);
      if (THREAD_GETMEM(self, p_condvar_avail) == 0
      && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
          || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
    {
      /* Count resumes that don't belong to us. */
      spurious_wakeup_count++;
      continue;
    }
      break;
    }

  __pthread_set_own_extricate_if(self, 0);

  /* Check for cancellation again, to provide correct cancellation
     point behavior */

  if (THREAD_GETMEM(self, p_woken_by_cancel)
      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
    THREAD_SETMEM(self, p_woken_by_cancel, 0);
    pthread_mutex_lock(mutex);
    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  }

  /* Put back any resumes we caught that don't belong to us. */
  while (spurious_wakeup_count--)
    restart(self);

  pthread_mutex_lock(mutex);
  return 0;
}rest

示例的解釋: 
call thread2:是線程2即t_b首先上鎖,即 pthread_mutex_lock(&mutex);鎖住了mutex使得此進程執行線程2中的臨界區的代碼,當執行到45行:if(i%3 != 0),此時i=1,知足此條件,則執行46行: pthread_cond_wait(&cond,&mutex); 這句是關鍵,pthread_cond_wait(&cond,&mutex)操做有兩步,是原子操做:第一 解鎖,先解除以前的pthread_mutex_lock鎖定的mutex;第二 掛起,阻塞並在等待對列裏休眠,即線程2掛起,直到再次被喚醒,喚醒的條件是由pthread_cond_signal(&cond);發出的cond信號來喚醒。 

call thread1:因爲pthread_cond_wait已經對線程2解鎖,此時另外的線程只有線程1,那麼線程1對mutex上鎖,若這時有多個線程,那麼線程間上鎖的順序和操做系統有關。 

thread1: 1:線程1上鎖後執行臨界區的代碼,當執行到if(i%3 == 0)此時i=1,不知足條件,則pthread_cond_signal(&cond);不被執行,那麼線程2仍處於掛起狀態,輸出thread1: 1後線程1由pthread_mutex_unlock(&mutex);解鎖。 

thread1: 2:這時此進程中只有2個線程,線程2處於掛起狀態,那麼只有線程1,則線程1又對mutex上鎖,此時一樣執行臨界區的代碼,並且i=2,不知足條件,pthread_cond_signal(&cond);不被執行,那麼線程2仍處於掛起狀態,輸出thread1: 1後線程1由pthread_mutex_unlock(&mutex);解鎖。 

call thread1:一樣由線程1上鎖,但此時i=3,知足條件pthread_cond_signal(&cond)被執行,那麼pthread_cond_signal(&cond)會發出信號,來喚醒處於掛起的線程2。 

thread2: 3:因爲pthread_cond_signal喚醒了線程2,即i=3知足條件,pthread_cond_wait(&cond,&mutex);被執行,那麼pthread_cond_wait(&cond,&mutex)此時也有一步操做:上鎖;即對線程2上鎖,此時的pthread_cond_wait(&cond,&mutex)的操做至關與pthread_mutex_lock(&mutex);那麼線程2繼續執行上鎖後的臨界區的代碼,並由pthread_mutex_unlock(&mutex);對線程2進行解鎖。 
隊列

.......進程

相關文章
相關標籤/搜索