线程同步--使用互斥量

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;
}

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(线程同步--使用互斥量)