linux 多线程编程 之 信号量互斥同步

            本文在上一篇的基础上进一步说明,Linux下多线程编程的互斥与同步。上一篇实现线程之间同步采用了互斥锁,同步采用条件变量,本文将说明如何使用信号量实现线程之间的互斥与同步。互斥锁只有0,1两中状态,适合于线程对共享资源的独占访问,很多时候每个资源可以同时被有限的线程访问,此时互斥锁将无法满足;条件变量同步也同样存在这种问题。信号量实际是一种非负整型计数器,可以很好的控制线程之间资源访问,互斥锁能实现的功能,信号量同样可以。

          信号量控制资源共享主要是PV原语操作, PV原语是对整数计数器信号量sem的操作。一次 P操作使 sem减一,而一次 V操作使sem 加一。进程(或线程)根据信号量的值来判断是否对公共资源具有访问权限。当信号量sem 的值大于等于零时,该进程(或线程)具有公共资源的访问权限;相反,当信号量 sem的值小于零时,该进程(或线程)就将阻塞直到信号量 sem的值大于等于 0 为止。

          Linux 实现了POSIX 的无名信号量,主要用于线程间的互斥同步。这里主要介绍几个常见函数。
                   ·   sem_init用于创建一个信号量,并能初始化它的值。
                   ·   sem_wait和sem_trywait相当于P操作,它们都能将信号量的值减一,两者的区别在  于若信号量小于零时,sem_wait将会阻塞进程,而 sem_trywait则会立即返回。
                   ·   sem_post相当于V操作,它将信号量的值加一同时发出信号唤醒等待的进程。
                   ·   sem_getvalue用于得到信号量的值。 
                   ·   sem_destroy用于删除信号量。
所需头文件  #include <semaphore.h>

函数原型  int sem_init(sem_t *sem,int pshared,unsigned int value)
sem:信号量
pshared:决定信号量能否在几个进程间共享。由于目前Linux还没有实现进程间共享信号量,所以这个值只能够取0
value:信号量初始化值
函数返回值 成功:0   ,出错:-1

 

所需头文件  #include <pthread.h>
函数原型
int sem_wait(sem_t *sem)
int sem_trywait(sem_t *sem)
int sem_post(sem_t *sem)
int sem_getvalue(sem_t *sem)
int sem_destroy(sem_t *sem)
函数传入值  sem:信号量
函数返回值 成功:0 ,出错:-1

从上面函数来看,实现线程之间同步信号量比互斥锁使用起来相对容易一些,操作简单,容易理解,适用范围广。

下面上一篇的问题用信号量来实现,线程使用部分没变,主要改变了对资源的控制方式:(代码本人亲自编译通过)

#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>

int g_Flag = 0;
sem_t sem_mutex;  // 用于互斥
sem_t sem_syn;    // 用于同步

void *thread1( void *arg );
void *thread2( void *arg );
int main()
{
	pthread_t tid1, tid2;
	int rc1, rc2;

	sem_init( &sem_mutex, 0, 1 );
	sem_init( &sem_syn, 0, 0 );
	printf( " Inter main !\n" );

	rc2 = pthread_create( &tid2, NULL, thread2, NULL );
	if( rc2 != 0 )
		 printf( " %s, %d \n", __func__, strerror( rc2 ) );

	rc1 = pthread_create( &tid1, NULL, thread1, &tid2 );
	if( rc1 != 0 )
		printf( " %s, %d \n", __func__, strerror(rc1) );
	printf( " Leave main!\n\n" );

	sem_wait( &sem_syn );   // 同步等待,阻塞
	exit( 0 );
}

void *thread1( void *arg )
{
	pthread_t *ptid = NULL;
	printf( " Enter thread1\n" );
	printf( " thread1 id: %u, g_Flag: %d \n", ( unsigned int )pthread_self(), g_Flag );
	
	if( sem_wait( &sem_mutex ) != 0)
	{
		perror(" pthread1 sem_mutex\n");
	}

	if( g_Flag == 2 )
	  	sem_post( &sem_syn );
	g_Flag  = 1;

	if( sem_post( &sem_mutex ) != 0)
	{
		perror( "pthread1 sem_post\n" );
	}
	printf( " thread1 id: %u, g_Flag: %d \n",( unsigned int )pthread_self(), g_Flag );
	printf( "Leave thread1 \n\n" );

	ptid = ( pthread_t *)arg;
	printf( " ptid = %u \n", *ptid );
	pthread_join( *ptid, NULL );
	pthread_exit(0 );
}

void *thread2( void *arg )
{
	printf( " Enter thread2 !\n" );
	printf( " thread2 id: %u , g_Flag: %d \n", ( unsigned int)pthread_self(), g_Flag );

	if( sem_wait( &sem_mutex ) != 0 )
	{
		perror( "thread2 sem_wait \n" );
	}
	
	if( g_Flag == 1 )
		sem_post( &sem_syn );

	g_Flag = 2;

	if( sem_post( &sem_mutex ) != 0)
	{
		perror( " thread2 sem_post\n" );
	}
	printf( " thread2 id: %u , g_Flag: %d \n", ( unsigned int )pthread_self(), g_Flag );
	printf( "Leave thread2 \n\n" );

	pthread_exit(0);
}



 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值