POSIX信号量与互斥锁

3种用于线程同步的机制: POSIX信号量,互斥锁和条件变量
一.POSIX信号量
常用的POSIX信号量函数如下
    int sem_init(sem_t *sem, int pshared, unsigned int value); //初始化一个信号量
    int sem_destroy(sem_t *sem); //销毁信号量
    
    int sem_wait(sem_t *sem); // 以原子操作的方式将信号量的值减1
    int sem_trywait(sem_t *sem); //非阻塞版本
    int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
    
    int sem_post(sem_t *sem); // 以原子操作方式将信号量的值加1
    

二.POSIX互斥锁
    互斥锁可以用来保护关键代码段,以确保独占式的访问.
POSIX互斥锁相关函数
    int pthread_mutex_destroy(pthread_mutex_t *mutex); //销毁互斥锁
    int pthread_mutex_init(pthread_mutex_t *restrict mutex,
              const pthread_mutexattr_t *restrict attr);

    //实际上只是把互斥锁的各个字段初始化为0          
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
      
    int pthread_mutex_lock(pthread_mutex_t *mutex);  //以原子操作方式给互斥锁加锁
    int pthread_mutex_trylock(pthread_mutex_t *mutex); //非阻塞版本
    int pthread_mutex_unlock(pthread_mutex_t *mutex); // 以原子操作方式给互斥锁解锁

三. 生产者消费者问题

#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>

#include <semaphore.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
	do \
	{	\
		perror(m); \
		exit(EXIT_FAILURE); \
	}while(0)
	
#define CONSUMERS_COUNT 1
#define PRODUCERS_COUNT 5
#define BUFFSIZE 10  // 缓冲区大小

int g_buffer[BUFFSIZE]; /// 产品ID保存在缓冲区中

unsigned short in=0;  // 从in位置放产品
unsigned short out=0;  // 从out的位置消费产品
unsigned short produce_id =0;  // 产品ID
unsigned short consume_id =0;  // 消费产品ID

sem_t  g_sem_full;  //full信号量
sem_t  g_sem_empty;  //empty信号量
pthread_mutex_t   g_mutex;  // 互斥锁


// 创建的线程ID保存在g_thread中
pthread_t g_thread[CONSUMERS_COUNT+PRODUCERS_COUNT];

///消费者
void* consume(void* arg)
{
	int num = (int)arg;
	int i;
	while(1)
	{
		printf("%d wait buffer not empty\n",num);
		sem_wait(&g_sem_empty);
		pthread_mutex_lock(&g_mutex);
		
		//打印仓库状态
		for(i=0;i<BUFFSIZE;++i)
		{
			printf("%02d ",i);
			if(g_buffer[i] == -1)
				printf("%s","null");
			else
				printf("%d",g_buffer[i]);
			if(i == out)
				printf("\t<--consume");
			printf("\n");
		}
		// 消费产品
		consume_id = g_buffer[out];
		printf("%d begin consume product %d\n",num,consume_id);
		g_buffer[out] = -1;  // 取走产品,得把缓冲区设置为-1
		out = (out+1)%BUFFSIZE;
		printf("%d end consume product %d\n",num,consume_id);
		
		
		pthread_mutex_unlock(&g_mutex);
		sem_post(&g_sem_full);
		sleep(1);
	}
	return NULL;
}

 生产者
void* produce(void* arg)
{
	int i;
	int num = (int)arg;
	while(1)
	{
		printf("%d wait buffer not full\n",num);
		sem_wait(&g_sem_full);
		pthread_mutex_lock(&g_mutex);
		
		// 打印仓库的状态
		for(i=0;i<BUFFSIZE;++i)
		{
			printf("%02d ",i);
			if(g_buffer[i] == -1)
				printf(" %s","null");
			else
				printf("%d ",g_buffer[i]);
			if(i == in)
				printf("\t<--produce");
			printf("\n");
		}
		// 生产产品
		printf("%d begin produce produce %d \n",num,produce_id);
		g_buffer[in] = produce_id;
		in = (in+1)%BUFFSIZE;
		printf("%d end produce product %d\n",num,produce_id++);
		
		pthread_mutex_unlock(&g_mutex);
		sem_post(&g_sem_empty);
		
		sleep(5);
	}
	return NULL;
}

int main(void )
{
	int i=0;
	for(i=0;i<BUFFSIZE;++i)
		g_buffer[i] = -1;  // 初始化仓库都为-1
	// 初始化信号量
	sem_init(&g_sem_full,0,BUFFSIZE); //g_sem_full 信号的初始值为BUFFSIZE
	sem_init(&g_sem_empty,0,0);
	//初始化互斥锁
	pthread_mutex_init(&g_mutex,NULL);
	
	/// 创建消费者线程
	for(i=0;i<CONSUMERS_COUNT;++i)
		pthread_create(&g_thread[i],NULL,consume,(void*)i);
	/// 创建生产者线程
	for(i=0;i<PRODUCERS_COUNT;++i)
		pthread_create(&g_thread[CONSUMERS_COUNT+i],NULL,produce,(void*)i);
	// 等待线程的结束	
	for(i=0;i<CONSUMERS_COUNT+PRODUCERS_COUNT;++i)
		pthread_join(g_thread[i],NULL);
	
	return 0;
}



四. 自旋锁与读写锁

1.自旋锁
    (1)自旋锁类似于互斥锁,它的性能比互斥锁更高
    (2)自旋锁与互斥锁很重要的一个区别在于,线程在申请自旋锁的时候,线程不会被挂起,处于忙等待状态
      int pthread_spin_destroy(pthread_spinlock_t *lock);
      int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
      int pthread_spin_lock(pthread_spinlock_t *lock);
      int pthread_spin_trylock(pthread_spinlock_t *lock);
      int pthread_spin_unlock(pthread_spinlock_t *lock);

2.读写锁
    (1)只要没有线程持有给定的读写锁用于写,那么任意数目线程可以持有读写锁用于读.
    (2)仅当没有线程持有某个给定的读写锁用于读或者用于写时才能分配读写锁用于写.
    (3)读写锁用于读称为共享锁,读写锁用于写称为排他锁.
    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
    int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
              const pthread_rwlockattr_t *restrict attr);
    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
   
    int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值