POSIX信号量和互斥锁

xiaoxiao2021-02-28  88

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

转载请注明原文地址: https://www.6miu.com/read-63786.html

最新回复(0)