线程同步

 

一、互斥量

互斥量从本质上说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。

互斥量用pthread_mutex_t数据类型表示,在使用互斥变量以前,必须首先对它进行初始化。可以把它设置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量),也可以通过调用pthread_mutex_init函数进行初始化,如果动态地分配互斥量(比如说malloc)那么在释放内存前需要调用pthread_mutex_destroy

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex)
//返回值:若成功返回0,否则返回错误编号

对互斥量进行加锁,需要调用pthread_mutex_lock,如果互斥量已经上锁,调用线程将阻塞直到互斥量被解锁,对互斥量解锁,需要调用pthread_mutex_unlock

#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)
//返回值:若成功返回0,否则返回错误编号

如果线程不希望被阻塞,它可以使用pthread_mutex_trylock尝试对互斥量进行加锁,如果调用pthread_mutex_trylock时互斥量处于未锁住状态,那么pthread_mutex_trylock将锁住互斥量,不会出现阻塞并返回0,否则pthread_mutex_trylock就会失败,不能锁住互斥量,而返回EBUSY。

struct foo
{
    int f_count;
    pthread_mutex_t f_lock;  
};

struct foo *foo_alloc(void)
{
    struct foo *fp;
    if((fp=malloc(sizeof(struct foo)))!=NULL)//动态地分配互斥量
    {
        fp->count=1;
        if(pthread_mutex_init(&fp->f_lock,NULL)!=0)
        {
            free(fp);
            return(NULL);
        }
    }
    return(fp);
}

void foo_hold(struct foo *fp)
{
    pthread_mutex_lock(&fp->f_lock);
    fp->f_count++;
    pthread_mutex_unlock(&fp->f_lock);
}

void foo_rele(struct foo *fp)
{
    pthread_mutex_lock(&fp->f_lock);
    if(--fp->f_count==0)
    {
        pthread_mutex_unlock(&fp->f_lock);
        pthread_mutex_destroy(&fp->f_lock);
        free(fp);
    }
    else 
        pthread_mutex_unlock(&fp->f_lock);
}

 

二、避免死锁

1.控制互斥量加锁顺序:总是让多个互斥量以相同的顺序加锁

2.合理安排锁的功能:如果锁的粒度太粗,就会出现很多线程阻塞等待相同的锁;如果锁的粒度太细,那么过多的锁开销会使系统性能受到影响,而且代码变得复杂。

三、读写锁

读写锁pthread_rwlock_t可以有三种状态:读模式下加锁状态,写模式下加锁状态,不加锁状态。一次只有一个线程可以占有写模式的读写锁pthread_rwlock_wrlock,但是多个线程可以同时占有读模式的读写锁pthread_rwlock_rdlock。

读写锁在使用之前必须初始化,在释放它们底层的内存前必须销毁。

#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwllock,const pthread_rwlockattr_t *restrict attr);;
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
#include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);//读模式下锁定读写锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);//写模式下锁定读写锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);//解锁

四、条件变量

条件变量pthread_cond_t通常被保存为全局变量,并和互斥锁合作,还需要和另一个全局变量 配合,这个全局变量用来构成各个条件。条件由互斥量保护,线程在改变条件状态前必须首先锁住互斥量。

条件变量在使用之前必须进行初始化,可以把常量PTHREAD_COND_INITIALIZER赋给静态分配的条件变量,但是如果条件变量是动态分配的,可以使用pthread_cond_init函数初始化。

使用pthread_cond_wait等待条件变为真,如果在给定时间内条件不能满足,会返回一个代表出错码的返回变量

int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);

pthread_cond_signal函数将唤醒等待该条件的某个线程,而pthread_cond_broadcast函数将唤醒等待该条件的所有线程。

int pthread_cond_signal(pthread_cond_t *cond);

int pthread_cond_broadcast(pthread_cond_t *cond);

struct msg
{
        struct msg *m_next;
};

struct msg *workq;//该全局变量构成各个条件
pthread_cond_t qready=PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock=PTHREAD_MUTEX_INITIALIZER;

void process_msg(void)
{
        struct msg *mp;
        for(;;)
        {
                pthread_mutex_lock(&qlock);
                while(workq==NULL)//当workq为NULL时,等待cond通知
                        pthread_cond_wait(&qready,&qlock);
                mp=workq;
                workq=mp->m_next;
                pthread_mutex_unlock(&qlock);
        }
}
void enqueue_msg(struct msg *mp)
{
        pthread_mutex_lock(&qlock);
        mp->m_next=workq;
        workq=mp;
        pthread_mutex_unlock(&qlock);
        pthread_cond_signal(&qready);
}

 个人感觉条件变量的作用在于发送消息通知程序条件已经满足,继续下面的程序,互斥量保护全局变量构成的条件,当条件不满足时,使用条件变量对应的函数来阻塞条件。

 

posted @ 2014-07-03 14:13  合唱团abc  阅读(182)  评论(0)    收藏  举报