POSIX信号量和互斥锁

POSIX信号量

1 创建信号量
sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
功能:初始化有名信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:用于初始化无名的信号量,注意无名信号量也可以用于不同进程间的线程通信,这取决于第二个参数,如果pshared非零就可以用于多个进程间通信,前提是这个无名信号量存在于共享内存区中。
2 删除信号量
int sem_close(sem_t *sem);
int sem_unlink(const char *name);
sem_close用于关闭打开的信号量。当一个进程终止时,内核对其上仍然打开的所有有名信号量自动执行这个操作。调用sem_close关闭信号量并没有把它从系统中删除它,POSIX有名信号量是随内核持续的。即使当前没有进程打开某个信号量它的值依然保持。直到内核重新自举或调用sem_unlink()删除该信号量。
3 信号量P操作
int sem_wait (sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
int sem_trywait (sem_t * sem);
1 sem_wait()用于获取信号量,首先会测试指定信号量的值,如果大于0,就会将它减1并立即返回,如果等于0,那么调用线程会进入睡眠,指定信号量的值大于0.
2 sem_trywait和sem_wait的差别是,当信号量的值等于0的,调用线程不会阻塞,直接返回,并标识EAGAIN错误。
3 sem_timedwait和sem_wait的差别是当信号量的值等于0时,调用线程会限时等待。当等待时间到后,信号量的值还是0,那么就会返回错误。其中 struct timespec *abs_timeout是一个绝对时间。
4 信号量V操作
int sem_post(sem_t *sem);
当一个线程使用完某个信号量后,调用sem_post,使该信号量的值加1,如果有等待的线程,那么会唤醒等待的一个线程。
5 获取当前信号量
int sem_getvalue(sem_t *sem, int *sval);
该函数返回当前信号量的值,通过sval输出参数返回,如果当前信号量已经上锁(即同步对象不可用),那么返回值为0,或为负数,其绝对值就是等待该信号量解锁的线程数。

POSIX互斥锁

多线程编程中,(多线程编程)可以用互斥锁(也称互斥量)可以用来保护关键代码段,以确保其独占式的访问,这有点像二进制信号量。POSIX互斥锁相关函数主要有以下5个:
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
这些函数第一个参数mutex指向要操作的目标互斥锁,成功时返回0,出错返回错误码
1. pthread_mutex_init用于初始化互斥锁,mutexattr用于指定互斥锁的属性,若为NULL,则表示默认属性。除了用这个函数初始化互斥所外,还可以用如下方式初始化:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER。
2 pthread_mutex_destroy用于销毁互斥锁,以释放占用的内核资源,销毁一个已经加锁的互斥锁将导致不可预期的后果。
3 pthread_mutex_lock以原子操作给一个互斥锁加锁。如果目标互斥锁已经被加锁,则pthread_mutex_lock则被阻塞,直到该互斥锁占有者把它给解锁。
4 pthread_mutex_trylock和pthread_mutex_lock类似,不过它始终立即返回,而不论被操作的互斥锁是否加锁,是pthread_mutex_lock的非阻塞版本。当目标互斥锁未被加锁时,pthread_mutex_trylock进行加锁操作;否则将返回EBUSY错误码。注意:这里讨论的pthread_mutex_lock和pthread_mutex_trylock是针对普通锁而言的,对于其他类型的锁,这两个加锁函数会有不同的行为。
5 pthread_mutex_unlock以原子操作方式给一个互斥锁进行解锁操作。如果此时有其他线程正在等待这个互斥锁,则这些线程中的一个将获得它。

下面是基于信号量和互斥锁的生产者消费者模型:

#include<pthread.h>
#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<semaphore.h>
#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>
#define ERR_EXIT(m) do{perror(m);exit(EXIT_FAILURE);}while(0)
#define CONSUMER_COUNT 2
#define PRODUCER_COUNT 5
#define BUFFSIZE 10
int g_buffer[BUFFSIZE];
unsigned int in=0;
unsigned int out=0;
unsigned product_id=0;
unsigned consumer_id=0;
sem_t g_sem_full;
sem_t g_sem_empty;
pthread_mutex_t g_mutex;
pthread_t g_thread[CONSUMER_COUNT+PRODUCER_COUNT];
void* consume(void *arg)
{
    int n=(int)((long)arg);
    while(1)
    {
        printf("%d consumer is waiting\n",n);
        sem_wait(&g_sem_empty);
        pthread_mutex_lock(&g_mutex);
         for(int i=0;i<BUFFSIZE;i++)
        {
             printf("%d ",i);
             printf("%d ",g_buffer[i]);
             if(i==out)printf("\t<--consume");
             printf("\n");
        }
        printf("out=%d\n",out);
        consumer_id=g_buffer[out];
        printf("%d thread %d is consumer %d\n",n,(int)pthread_self(),consumer_id);
        g_buffer[out]=-1;
        out=(out+1)%BUFFSIZE;
        printf("end consumer %d\n",consumer_id);
        pthread_mutex_unlock(&g_mutex);
        sem_post(&g_sem_full);
        sleep(1);
    }
    return NULL;
}
void* produce(void *arg)
{
    int n=(int)((long)arg);
    while(1)
    {
        printf("%d produce is waiting\n",n);
        sem_wait(&g_sem_full);
        pthread_mutex_lock(&g_mutex);
        for(int i=0;i<BUFFSIZE;i++)
        {
             printf("%d ",i);
             printf("%d",g_buffer[i]);
             if(in==i)printf("\t-->produce");
             printf("\n");
        }
        printf("in=%d\n",in);
        printf("%d thread %d is product %d\n",n,(int)pthread_self(),product_id);
        g_buffer[in]=product_id;
        in=(in+1)%BUFFSIZE;
        printf("end produce product %d\n",product_id++);
        pthread_mutex_unlock(&g_mutex);
        sem_post(&g_sem_empty);
        sleep(5);
    }

}
int main()
{
    for(int i=0;i<BUFFSIZE;i++)g_buffer[i]=-1;
    sem_init(&g_sem_full,0,BUFFSIZE) ;
    sem_init(&g_sem_empty,0,0);
    pthread_mutex_init(&g_mutex,NULL);
    int i=0;
    for(i=0;i<CONSUMER_COUNT;i++)
    {
        pthread_create(&g_thread[i],NULL,consume,(void*)((long) i));
    }
    for(i=0;i<PRODUCER_COUNT;i++)
    {
        pthread_create(&g_thread[i+CONSUMER_COUNT],NULL,produce,(void*)((long) i));
    }
    for(i=0;i<CONSUMER_COUNT+PRODUCER_COUNT;i++)pthread_join(g_thread[i],NULL);
    sem_destroy(&g_sem_full);
    sem_destroy(&g_sem_empty);
    pthread_mutex_destroy(&g_mutex);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值