線程同步–使用互斥量

來源:互聯網
上載者:User

1.初始化與銷毀互斥量

Linux使用pthread_mutex_t 資料類型表示互斥量,並使用pthread_mutex_init函數對互斥量進行初始化。

 

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t * restrict mutex,const pthread_mutexattr * restrict attr);

 

第一個參數是互斥量的指標,互斥量在該函數內被初始化。第二個參數是互斥量的屬性,一般置為NULL。

 

Linux還提供了另一種初始化互斥量的方法,使用者可以將互斥量設定為PTHREAD_MUTEX_INITIALIZER,這種方法有個局限性,那就是如果互斥量是使用動態分配記憶體的方法得到的,那麼就不能使用如下方法初始化訊號量。

pthread_mutex_t  * mutex;

mutex=(pthead_mutex_t * )malloc(sizeof(pthread_mutex_t));

mutex=PTHREAD_MUTEX_INITIALIZER;

 

以上的初始化是錯誤的。原因在於linux將pthread_mutex_t 類型定義為結構體,而PTHREAD_MUTE_INITIALIZER常量相當於已經設定好的結構體變數中每一個成員變數的值。顯而易見,一個已經定義的結構體對象可以使用這種方法,而一個利用malloc得來的結構體對象不能夠使用這種方法。

如果要使用PTHREAD_MUTEX_INITIALIZER,可以這樣用。

pthread_mutex_t   mutex=PTHREAD_MUTEX_INITIALIZER;

 

當一個互斥量不再使用時,使用如下函數用如下函數將其銷毀。

 

#include <pthread.h>

int pthread_mutex_destroy(pthread_mutex_t * mutex);

 

2.得到與釋放互斥量

 

#include <pthread.h>

int pthread_mutex_lock(pthread_mutex_t * mutex);

int pthread_mutex_trylock(pthread_mutex_t * mutex);

int pthread_mutex_unlock(pthread_mutex_t * mutex);

 

第一個函數在所要求的互斥量的鎖已被其他線程所取得的情況下,會阻塞調用線程。第二個函數不會阻塞調用線程,會立即返回EBUSY。表示鎖處於繁忙狀態。

 

用第二個函數實現一個非阻塞的加鎖函數版本,用於忙等待一個互斥量的鎖。

 

……

while(pthread_mutex_trylock(&mutex)==EBUSY);

……

 

 

3.執行個體

 

該程式維護一個任務隊列,其本質是一個鏈表。兩個線程掃描鏈表,將屬於自己的任務從工作清單中摘下。

兩個線程分別對鏈表進程讀操作。為了防止可中斷的讀寫之間造成的資料不一致的錯誤,使用互斥量。

 

//mutex_list.c

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

#include <pthread.h>

#include <string.h>
 
#define MAX_ITEM 3 /* 每次最多取三個任務 */

 
typedef struct job * Job;

 
/* 鏈表節點結構 */

struct job{

    pthread_t tid; 

    Job next; 

    int val; 

};

 
pthread_mutex_t q_lock = PTHREAD_MUTEX_INITIALIZER; /* 全域變數鎖 */

 
int insert(Job *head, int val, pthread_t tid)

{

    Job p, q;

 
    p = *head; /* 頭指標 */

 
    if(p != NULL){ /* 判斷空鏈表的情況 */

        while(p->next != NULL){

            p = p->next;     
        }     
    }     
 
    q = (struct job *)malloc(sizeof(struct job)); 

    if(q == NULL){

        perror("fail to malloc");

        return -1;

    }

             
    q->next = NULL;

    q->val = val;

    q->tid = tid; 

    p->next = q; 

     
    if(p == NULL){ /* 設定鏈表頭 */

        *head = q;

        return 0;     
    }

     
    p->next = q; 

 
    return 0;

}

 
void get_job(Job head, Job task, int *count)

{

    struct job *p, *q;

    pthread_t tid;
 
    q = head; 

    p = q->next; 

   
    tid = pthread_self();
 
    while(p != NULL){ 

        if(tid == p->tid){

            q->next = p->next;

            p->next = task; 

            task = p; 

            p = q->next;

            *count++; 

        }else{

            q = p;

            p = p->next;

        }

    }

}

 
int free_job(Job head)

{

    Job p, q;

 
    for(p = head; p != NULL; p = p->next){ 

        q = p;

         p = p->next;

            free(q);

    }

 
    return 0;

}

 
void print(Job head)

{

    Job p;

     
    for(p = head; p != NULL; p = p->next) 

        printf("thread %u: %d/n", p->tid, p->val);

}

 
void * tfn7(void * arg)

{

    int count; 

    struct job * task = NULL; 

    pthread_t tid;

 
    tid = pthread_self();

     
    count = 0;

    while(count < MAX_ITEM)

        if(pthread_mutex_trylock(&q_lock) == 0){ 

            get_job((Job) arg, task, &count);

            pthread_mutex_unlock(&q_lock); 

        }

 
    print((Job) arg);

 
    if(free_job(task) == -1)

        exit(1);

 
    return (void *)0;

}

 
int main(void)

{

    struct job * item; 

    pthread_t tid1, tid2;

    int i;
    int err;

         
    item = (struct job *)malloc(sizeof(struct job)); 

    item->next = NULL;

    item->val = 0;

    item->tid = -1;

     
     
    if((err = pthread_create(&tid1, NULL, tfn7, item)) != 0){ 

        printf("fail to create thread %s/n", strerror(err));

        exit(0);     
    }

    if((err = pthread_create(&tid2, NULL, tfn7, item)) != 0){ 

        printf("fail to create thread %s/n", strerror(err));

        exit(0);     
    }

 
    printf("===the 1st put===/n"); 

 
    pthread_mutex_lock(&q_lock); 

    for(i = 0; i < 2; i++){

        if(insert(&item, i, tid1) == -1)

            exit(1);

        if(insert(&item, i + 1, tid2) == -1)

            exit(1);

    }

         
    if(insert(&item, 10, tid1) == -1)

        exit(1);

         
    pthread_mutex_unlock(&q_lock); 

     

    sleep(5); 

    /* 休眠,保證線程可以取走任務節點,在這裡不能使用pthread_join函數
                 *因為隊列中只有兩個節點屬於線程2,未取走3個節點線程是不會退出的
                 *所以pthread_join函數會導致死結

    */

     
    printf("===the 2nd put===/n");

     
    pthread_mutex_lock(&q_lock); 

    if(insert(&item, 9, tid2) == -1)

        exit(1);

    pthread_mutex_unlock(&q_lock); 

     
    err = pthread_join(tid1, NULL); 

    if(err != 0){

        printf("can¡¯t join thread %s/n", strerror(err));

        exit(1);     
    }

    err = pthread_join(tid2, NULL); 

    if(err != 0){

        printf("can¡¯t join thread %s/n", strerror(err));

        exit(1);     
    }

     
    printf("main thread done/n"); 

    if(item->next == NULL) 

        printf("No job in the queue/n");     
    free(item); 

 
    return 0;

}

 

 

 

 

 

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.