您的位置:首页 > 其它

IPC通信:Posix信号灯

2012-04-18 16:32 267 查看
  信号灯用来实现同步——用于多线程,多进程之间同步共享资源(临界资源)。信号灯分两种,一种是有名信号灯,一种是基于内存的信号灯。有名信号灯,是根据外部名字标识,通常指代文件系统中的某个文件。而基于内存的信号灯,它主要是把信号灯放入内存的,基于内存的信号灯,同步多线程时,可以放到该多线程所属进程空间里;如果是同步多进程,那就需要把信号灯放入到共享内存中(方便多个进程访问)。

  有名信号灯和基于内存的信号灯,具体区别体现在创建和销毁两个函数。有名信号灯使用sem_open和sem_close函数。基于内存的信号灯使用sem_init和sem_destroy函数。sem_init的参数可以控制是同步多线程,还是多进程;且该函数只能调用1次,因为调用后信号灯就存在了( 内存指针存在)。一般,使用基于内存的信号灯同步同进程多线程,使用有名信号灯同步多进程。

有名信号灯同步多线程:

1.sem_open函数。
功能:创建并初始化信号灯,如果存在就返回存在的信号灯。
头文件:#include <semaphore.h>
函数原型:sem_t * sem_open(const char * name,int oflag,mode_t mode,unsigned int value);
或者:sem_t * sem_open(const char * name,int oflag);
参数:name是给信号灯指定一个名字。oflag的值为O_CREAT,表示如果信号灯不存在,创建信号灯;为O_CREAT|O_EXCL,如果信号灯不存在报错。后面两个参数,只有新建信号灯时使用。mode为信号灯的权限(0644),value为信号灯的值。
返回值:成功时,返回信号灯的指针,错误返回SEM_FAILED

2.sem_close函数。
功能:关闭引用信号灯,信号灯引用计数减1。
头文件:#include <semaphore.h>
函数原型:int sem_close(sem_t * sem)
参数:sem为信号灯的指针
返回值:成功时,返回0,失败,-1
注:每个信号灯有一个引用计数器记录当前打开次数.关闭一个信号灯并没有将它从系统中删除,而是信号灯引用计数减1

3.sem_unlink函数
功能:信号灯引用计数为0时,从系统中删除信号灯。
头文件:#include <semaphore.h>
函数原型:int sem_close(const char *name)
参数:name为信号灯的外部名字
返回值:成功时,返回0,失败,-1

4.sem_wait/sem_trywait函数
功能:等待共享资源,信号灯值为0就睡眠,信号灯值大于0,就使用共享资源,信号灯值减1。sem_trywait当信号灯值为0时,不睡眠,报错。
头文件:#include <semaphore.h>
函数原型:int sem_wait(sem_t *sem),int sem_trywait(sem_t *sem)
参数:sem为信号灯指针
返回值:成功时,返回0,失败,-1

5.sem_getvalue函数
功能:获得信号灯的值
头文件:#include <semaphore.h>
函数原型:int sem_getvalue(sem_t *sem,int *valp)
参数:sem为信号灯指针,valp为信号灯的值
返回值:成功时,返回0,失败,-1

6.sem_post函数
功能:使用完共享资源后,信号灯值加1,唤醒其他睡眠的。
头文件:#include <semaphore.h>
函数原型:int sem_post(sem_t *sem)
参数:sem为信号灯指针
返回值:成功时,返回0,失败,-1


示例代码:

/*semopen_pth.c*/
#include <stdio.h>
#include <semaphore.h>
#include <fcntl.h>
#include <pthread.h>

void print();
void * thread_function(void *arg);
sem_t * sem;

int main(int argc,char * argv[])
{
int n=0;
pthread_t tid;
if(argc != 2)
{
printf("Usage:%s name.\n",argv[0]);
exit(0);
}
//init semaphore
sem=sem_open(argv[1],O_CREAT,0644,3);
while(n++<5)
{
if((pthread_create(&tid,NULL,thread_function,NULL))!=0)
{
printf("can't create pthread.\n");
exit(0);
}
}
pthread_join(tid,NULL); //主线程需要等会其它线程
sem_close(sem);
sem_unlink(argv[1]);
return 0;
}

void * thread_function(void *arg)
{
sem_wait(sem);
print();
sleep(1); //因为共享段执行过快,不能达到同步效果,所以需要睡眠
sem_post(sem);
printf("finish, pthread_id is %d\n",pthread_self());
}

void print()
{
int value;
printf("pthread_id is %d, get the resource\n",pthread_self());
sem_getvalue(sem,&value);
printf("now,the semaphore value is %d\n",value);
}


编译并执行:

root@linux:/mnt/hgfs/C_libary# gcc -lpthread -o semopen_pth semopen_pth.c
semopen_pth.c: In function ‘main’:
semopen_pth.c:17: warning: incompatible implicit declaration of built-in function ‘exit’
semopen_pth.c:26: warning: incompatible implicit declaration of built-in function ‘exit’
semopen_pth.c: In function ‘thread_function’:
semopen_pth.c:41: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘pthread_t’
semopen_pth.c: In function ‘print’:
semopen_pth.c:47: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘pthread_t’
root@linux:/mnt/hgfs/C_libary#
注:产生了一些警告,先不管这些,看看是否能运行
root@linux:/mnt/hgfs/C_libary# ./semopen_pth sem
pthread_id is -1217336464, get the resource
now,the semaphore value is 2
pthread_id is -1225729168, get the resource
now,the semaphore value is 1
pthread_id is -1234121872, get the resource
now,the semaphore value is 0
finish, pthread_id is -1217336464
finish, pthread_id is -1225729168
finish, pthread_id is -1234121872
pthread_id is -1242514576, get the resource
now,the semaphore value is 2
pthread_id is -1250907280, get the resource
now,the semaphore value is 1
finish, pthread_id is -1242514576
finish, pthread_id is -1250907280
root@linux:/mnt/hgfs/C_libary#


有名信号灯同步多进程:

  unix网络编程第二卷,如是说不同进程(不管是否彼此有无亲缘关系),他们都可以访问同一个信号灯,只是需要在sem_open的时候传入的名字是一样就行。在有亲缘关系时,Posix中的fork如是描述,在父进程中打开的任何信号灯,仍应在子进程中打开。

示例代码:

/*semopen_pro.c*/
#include <stdio.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void print();
sem_t * sem;

int main(int argc,char * argv[])
{
int n=0,j;
pid_t pid;

if(argc != 2)
{
printf("Usage:%s name.\n",argv[0]);
exit(0);
}

//该信号灯不会因为不同进程而不同。
sem=sem_open(argv[1],O_CREAT,0644,3);
while(n++<5)
{
pid = fork();
if(pid == 0)
{
sem_wait(sem);
print();
sleep(1);
sem_post(sem);
printf("finish,the pid is %d\n",getpid());
exit(0);
}
}

j=0;

//等待所有子进程退出
while(j++<5)
wait(NULL);
sem_close(sem);
sem_unlink(argv[1]);
return 0;
}

void print()
{
int value;
printf("pid is %d, get the resource\n",getpid());
sem_getvalue(sem,&value);
printf("now,the semaphore value is %d\n",value);
}


编译并执行:

root@linux:/mnt/hgfs/C_libary# gcc -o semopen_pro semopen_pro.c
semopen_pro.c: In function ‘main’:
semopen_pro.c:19: warning: incompatible implicit declaration of built-in function ‘exit’
semopen_pro.c:34: warning: incompatible implicit declaration of built-in function ‘exit’
/tmp/ccUECdL7.o: In function `main':
semopen_pro.c:(.text+0x5d): undefined reference to `sem_open'
semopen_pro.c:(.text+0x81): undefined reference to `sem_wait'
semopen_pro.c:(.text+0x9f): undefined reference to `sem_post'
semopen_pro.c:(.text+0x107): undefined reference to `sem_close'
semopen_pro.c:(.text+0x117): undefined reference to `sem_unlink'
/tmp/ccUECdL7.o: In function `print':
semopen_pro.c:(.text+0x14e): undefined reference to `sem_getvalue'
collect2: ld returned 1 exit status
注:sem_XXX函数不是标准库函数,链接时需要指定库-lrt or -pthread.
root@linux:/mnt/hgfs/C_libary# gcc -lrt -o semopen_pro semopen_pro.c
semopen_pro.c: In function ‘main’:
semopen_pro.c:19: warning: incompatible implicit declaration of built-in function ‘exit’
semopen_pro.c:34: warning: incompatible implicit declaration of built-in function ‘exit’
root@linux:/mnt/hgfs/C_libary# ./semopen_pro sem
pid is 5262, get the resource
now,the semaphore value is 2
pid is 5263, get the resource
now,the semaphore value is 1
pid is 5264, get the resource
now,the semaphore value is 0
finish,the pid is 5262
pid is 5265, get the resource
now,the semaphore value is 0
finish,the pid is 5263
pid is 5266, get the resource
now,the semaphore value is 0
finish,the pid is 5264
finish,the pid is 5265
finish,the pid is 5266
root@linux:/mnt/hgfs/C_libary#


基于内存的信号灯同步多线程:

sem_init()
功能:初始化信号灯。
头文件:#include <semaphore.h>
函数原型:int sem_open(sem_t * sem,int shared,unsigned int value);
参数:sem为信号灯指针,shared是指同步多线程还是多进程(0:多线程,其他:多进程),value为信号量值
返回值:成功时,返回0,失败时,返回-1

sem_destroy()
功能:关闭信号
头文件:#include <semaphore.h>
函数原型:int sem_destroy(sem_t * sem)
参数:sem为信号灯的指针
返回值:成功时,返回0,失败,-1


示例代码:

/*seminit_pth*/
#include <stdio.h>
#include <semaphore.h>
#include <fcntl.h>
#include <pthread.h>

void print();
void * thread_function(void *arg);
sem_t sem;

int main(int argc,char * argv[])
{
int n=0;
pthread_t tid;
//init semaphore
sem_init(&sem,0,3);
while(n++<5)
{
if((pthread_create(&tid,NULL,thread_function,NULL))!=0)
{
printf("can't create pthread.\n");
exit(0);
}
}
pthread_join(tid,NULL);
sem_destroy(&sem);
return 0;
}

void * thread_function(void *arg)
{
sem_wait(&sem);
print();
sleep(1); //
sem_post(&sem);
printf("finish, pthread_id is %d\n",pthread_self());
}

void print()
{
int value;
printf("pthread_id is %d, get the resource\n",pthread_self());
sem_getvalue(&sem,&value);
printf("now,the semaphore value is %d\n",value);
}


编译运行:

root@linux:/mnt/hgfs/C_libary# gcc -lrt -o seminit_pth seminit_pth.c
seminit_pth.c: In function ‘main’:
seminit_pth.c:21: warning: incompatible implicit declaration of built-in function ‘exit’
seminit_pth.c: In function ‘thread_function’:
seminit_pth.c:35: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘pthread_t’
seminit_pth.c: In function ‘print’:
seminit_pth.c:41: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘pthread_t’
root@linux:/mnt/hgfs/C_libary#
root@linux:/mnt/hgfs/C_libary# ./seminit_pth
pthread_id is -1224959120, get the resource
now,the semaphore value is 2
pthread_id is -1233351824, get the resource
now,the semaphore value is 1
pthread_id is -1241744528, get the resource
now,the semaphore value is 0
finish, pthread_id is -1224959120
finish, pthread_id is -1233351824
finish, pthread_id is -1241744528
pthread_id is -1250137232, get the resource
now,the semaphore value is 2
pthread_id is -1216566416, get the resource
now,the semaphore value is 1
finish, pthread_id is -1250137232
finish, pthread_id is -1216566416
root@linux:/mnt/hgfs/C_libary#
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: