Linux多线程编程——线程的同步

POSIX信号量
posix信号量不同于IPC中的信号量 
常用的posix信号量函数
 
#include <semaphore.h>
int sem_init(sem_t* sem,int pshared,unsigned int value);
//初始化一个信号量,pshared参数指定信号量的类型,若为0,表示信号量为当前进程的局部信号量,否则,该信号量就可以在多个进程之间共享。value参数指定信号量的初始值。
 
int sem_destroy(sem_t* sem);
//销毁一个信号量,释放它所占有的内核资源
 
int sem_wait(sem_t* sem);
//让信号量的值减一,如果信号量的值为0,则阻塞,直到信号量的值为非0.
 
int sem_trywait(sem_t* sem);
//sem_wait的非阻塞版本,若信号量的值为0,返回一个错误值 -1,并设置errno为EAGAIN.
 
int sem_post(sem_t* sem);
//让信号量的值加1,当信号量的值大于0时,其他正在调用sem_wait的函数将被唤醒。
 
上面这写函数成功返回0,失败返回-1.
互斥锁

互斥量相当与锁,在使用共享资源时,对它加锁,使用完后,释放锁,在加锁期间,其他的线程不能对该共享资源进行操作.

数据类型:pthread_mutex_t

相关API

初始化和销毁互斥量

初始化一个互斥量时也可以赋值为PTHREAD_MUTEX_INITIALIZER

 

int pthread_mutex_init(pthread_mutext_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

//attr设置为NULL,代表以默认属性初始化互斥量

 

int pthread_mutex_destroy(pthread_mutex_t *mutex);

 

加锁

int pthread_mutex_lock(pthread_mutex_t *mutex);

//对互斥量加锁,若互斥量已加锁,则会阻塞,直到信号量解锁,成功返回0,

 

int pthread_mutex_trylock(pthread_mutex_t *mutex);

//如果信号量没被锁,则加锁,并返回0,若信号已被锁,则不会阻塞,返回一个非0值

 

int pthread_mutex_unlock(pthread_mutex_t *mutex);

 

int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,const struct timespec *restrict tsptr);

//当线程试图获取一个已经加锁的互斥量时,该函数可以设置等待时间,若在该时间内,互斥量被解锁,则调用该函数的线程可以继续运行,若没有解锁,则该函数不会对互斥量加锁,而是返回一个错误代码ETIMEDOUT,成功返回0

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

struct foo
{
    int f_count;
    pthread_mutex_t f_lock;
    int f_id;
};

struct foo* foo_alloc(int id)
{
    struct foo * fp;
    if((fp=malloc(sizeof(struct foo))!=NULL)
    {
        fp->f_count=1;
        fp->f_id=id;
        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);
    }
}

读写锁

读写锁有三种状态,加读锁,加写锁,不加锁,当位于写锁时,所有企图对读写锁加锁(无论时加读锁还是写锁)的线程都会阻塞,当位于加读锁时,所有试图对其加读锁的线程可以继续运行,但是加写锁的线程会阻塞。当读写锁位于读状态时,如果有一线程试图对其加写锁,那么读写锁通常会阻塞随后的加读锁请求,这样可以避免读模式锁长期占用,而写模式锁请求得不到满足。

数据类型  pthread_rwlock_t

#include <pthread.h>

int pthread_rwclock_init(pthread_rwlock_t *restrict rwlock,const pthread_relockattr_t *restrict attr);   //初始化一个读写锁,要先分配内存。

int pthread_rwclock_destroy(pthread_rwlock_t *rwlock)    //销毁锁   。2个函数成功返回0

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);   //加读锁

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); //加写锁

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); //解锁 若成功都返回0

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);  //成功返回0

 

条件变量

如果说互斥锁用于同步线程对共享数据的访问,那么条件变量就是用于同步共享数据的值。

#include <pthread.h>

int pthread_cond_init(pthread_cond_t* cond,pthread_condattr_t* cond_attr);

初始化一个条件量,若cond_attr为NULL,则以默认熟悉初始化,还可以pthread_cond_t cond=PTHREAD_COND_INITIALIZER;

 

int pthread_cond_destroy(pthread_cond_t* cond);

int pthread_cond_signal(pthread_cond_t* cond);

唤醒一个等待该条件变量的线程

int pthread_cond_broadcast(pthread_cond_t* cond);

唤醒所有等待该条件变量的线程

 

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

等待目标条件变量,mutex用来保证该函数操作的原子性,在使用pthread_cond_wait函数之前,需保证对mutex加锁。该函数执行时,把调用线程加入条件变量的等待队列。调用完后需要对mutex解锁。

上面的函数成功返回0,失败返回错误代码。

下面是一个线程同步机制的包装类

#include <exception>
#include <pthread.h>
#include <semphore.h>

class sem{
public:
    sem(unsigned int val=0){
        if(sem_init(&m_sem,0,val)!=0){
            throw std::exception();  //constructor don't have return val,if error,throw a exception
        }
    }

    ~sem(){
        sem_destroy(&m_sem);
    }

    //equal p operation
    bool wait(){
        return sem_wait(&m_sem)==0; 
    }

    //equal v operation
    bool post(){
        return sem_post(&m_sem)==0;
    }
private:
    sem_t m_sem;


};

class locker{
public:
    locker(){
        if(pthread_mutex_init(&m_mutex,NULL)!=0){
            throw std::exception();
        }
    }

    ~locker(){
        pthread_mutex_destroy(&m_mutex);
    }

    bool lock(){
        return pthread_mutex_lock(&m_mutex)==0;
    }

    bool unlock(){
        return pthread_mutex_unlock(&m_mutex)==0;
    }
private:
    pthread_mutex_t m_mutex;
};

class cond{
public:
    cond(){
        if(pthread_mutex_init(&m_mutex,NULL)!=0){
            throw std::exception();
        }

        if(pthread_cond_init(&m_cond,NULL)!=0){
            pthread_mutex_destroy(&m_mutex);
            throw std::exception();
        }
    }

    ~cond(){
        pthread_mutex_destroy(&m_mutex);
        pthread_cond_destroy(&m_cond);
    }

    bool wait(){
        int ret=0;
        pthread_mutex_lock(&m_mutex);
        ret=pthread_cond_wait(&m_cond,&m_mutex);
        pthread_mutex_unlock(&m_mutex);
        return ret==0;
    }

    bool signal(){
        return pthread_cond_signal(&m_cond)==0;
    }

private:
    pthread_mutex_t m_mutex;
    pthread_cond_t m_cond;
};

 

posted @ 2017-08-23 11:54  CodeUniverse  阅读(680)  评论(0编辑  收藏  举报