线程间同步实现--通过互斥锁和条件变量

信号量是一种用于提供不同进程或一个给定进程的不同线程间同步手段。
在Posix中,已经有一套信号接口,用于同一个进程中不同线程同步,其接口为:

int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
int sem_destroy(sem_t *sem);
int sem_getvalue(sem_t *sem);

但Posix标准实现信号量的主要的目的是提供一种进程间同步的方式,注意重点是解决进程间,不过信号量也可以用于线程间同步。
进程间同步通过有名信号量(sem_open(), sem_close(), sem_unlink(), sem_wait(), sem_post(), sem_getvalue(), sem_trywait())
线程间同步一般通过互斥锁和条件变量来实现,但具体情况,还要看应用场景。
下面主要介绍通过互斥锁和条件变量实现信号实现,代码比较简单:

#ifndef __DL_SEMA_H__
#define __DL_SEMA_H__


#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif

typedef void*   dl_sema_t;

extern int
dl_sema_create(dl_sema_t *pSema, unsigned int init_cnt);

extern int
dl_sema_destroy(dl_sema_t sema);

extern int
dl_sema_p(dl_sema_t sema, int timeout);

extern int
dl_sema_v(dl_sema_t sema);

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif
#endif /*  __DL_SEMA_H__ */


#include <pthread.h>
#include <stdlib.h>
#include <sys/time.h>           /* gettimeofday() */
#include "dl_sema.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif

#define SEMA_MAGIC              0xF147258F

struct sema_info{
        unsigned int magic;
        int     cnt;
        pthread_mutex_t mutex;
        pthread_cond_t  cond;
};

/* abstime = millsec + the current time */
void dl_gettime(struct timespec *abstime, int millsec)
{
        long sec, nsec;
        struct timeval cur_time;

        gettimeofday(&cur_time, 0);
        nsec = cur_time.tv_usec * 1000;
        sec = cur_time.tv_sec;

        nsec += (millsec%1000)*1000000;
        abstime->tv_nsec = nsec % 1000000000;

        sec += millsec/1000;
        sec += nsec / 1000000000;
        abstime->tv_sec = sec;
}

/* create a semaphore with init_cnt */
int dl_sema_create(dl_sema_t *pSema, unsigned int init_cnt)
{
        struct sema_info *sema;

        if(!pSema) return -1;

        sema = malloc(sizeof(struct sema_info));
        if(!sema) return -1;

        if(pthread_mutex_init(&(sema->mutex), 0) != 0){
                free(sema);
                return -1;
        }

        if( pthread_cond_init(&(sema->cond), 0) != 0){
                pthread_mutex_destroy(&(sema->mutex));
                free(sema);
                return -1;
        }

        sema->cnt = init_cnt;
        sema->magic = SEMA_MAGIC;

        *pSema = sema;
        return 0;
}


int dl_sema_p(dl_sema_t sema, int timeout)
{
        struct sema_info *psema = (struct sema_info*) sema;
        int ret = 0;

        if(!psema || (psema->magic != SEMA_MAGIC) ) return -1;

        pthread_mutex_lock(&(psema->mutex));
        if(psema->cnt <= 0){
                /* wait forever */
                if(timeout == 0){
                        while(psema->cnt <= 0){
                                if((ret = pthread_cond_wait(&(psema->cond), &(psema->mutex))) != 0){
                                        pthread_mutex_unlock(&(psema->mutex));
                                        return ret;
                                }
                        }
                }
                else {
                        struct timespec abs_time;
                        dl_gettime(&abs_time, timeout);
                        while(psema->cnt <= 0){
                                ret = pthread_cond_timedwait(&(psema->cond),
                                                                &(psema->mutex),
                                                                &abs_time);
                                if(ret != 0){
                                        pthread_mutex_unlock(&(psema->mutex));
                                        return ret;
                                }
                        }
                }
        }

        psema->cnt--;
        pthread_mutex_unlock(&(psema->mutex));

        return 0;
}

int dl_sema_v(dl_sema_t sema)
{
        int ret = 0;
        struct sema_info* psema = (struct sema_info*)sema;

        if(!psema || (psema->magic != SEMA_MAGIC) ) return -1;

        pthread_mutex_lock(&(psema->mutex));
        psema->cnt++;

        ret = pthread_cond_signal(&(psema->cond));
        if(ret != 0){
                psema->cnt--; /* roll back */
                pthread_mutex_unlock(&(psema->mutex));
                return ret;
        }
        pthread_mutex_unlock(&(psema->mutex));

        return 0;
}

int dl_sema_destroy(dl_sema_t sema)
{
        struct sema_info* psema = (struct sema_info*)sema;
        int ret = 0;

        if(!psema || (psema->magic != SEMA_MAGIC) ) return -1;
        psema->magic = 0;

        if((ret = pthread_mutex_destroy(&(psema->mutex))) != 0) return ret;
  
        if((ret = pthread_cond_destroy(&(psema->cond))) != 0) return ret;

        free(psema);
        return 0;
}

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif

//简单测试代码:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include "dl_sema.h"


void *thread_1(void *arg)
{
        int ret;
        dl_sema_t sema = (dl_sema_t)arg;
        ret = dl_sema_p(sema, 3000);/* 3s timeout */
        if(ret == 0)printf("the semaphore come up !\n");
        dl_sema_destroy(sema);
        return 0;
}


void *thread_2(void *arg)
{
        dl_sema_t sema = (dl_sema_t)arg;
        dl_sema_v(sema);
        printf("OK!!!!\n");
        return 0;
}


int main(int argc, char**argv)
{
        pthread_t thid;
        dl_sema_t sema;

        if(dl_sema_create(&sema, 0))
                printf("dl_sema_init failed.\n");

        pthread_create(&thid, 0, thread_1, sema);
        pthread_create(&thid, 0, thread_2, sema);

        sleep(5);
        return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值