IPC通信:Posix信号灯
信号灯用来实现同步——用于多线程,多进程之间同步共享资源(临界资源)。信号灯分两种,一种是有名信号灯,一种是基于内存的信号灯。有名信号灯,是根据外部名字标识,通常指代文件系统中的某个文件。而基于内存的信号灯,它主要是把信号灯放入内存的,基于内存的信号灯,同步多线程时,可以放到该多线程所属进程空间里;如果是同步多进程,那就需要把信号灯放入到共享内存中(方便多个进程访问)。
有名信号灯和基于内存的信号灯,具体区别体现在创建和销毁两个函数。有名信号灯使用sem_open和sem_close函数。基于内存的信号灯使用sem_init和sem_destroy函数。sem_init的参数可以控制是同步多线程,还是多进程;且该函数只能调用1次,因为调用后信号灯就存在了( 内存指针存在)。一般,使用基于内存的信号灯同步同进程多线程,使用有名信号灯同步多进程。
有名信号灯同步多线程:
1 1.sem_open函数。 2 功能:创建并初始化信号灯,如果存在就返回存在的信号灯。 3 头文件:#include <semaphore.h> 4 函数原型:sem_t * sem_open(const char * name,int oflag,mode_t mode,unsigned int value); 5 或者:sem_t * sem_open(const char * name,int oflag); 6 参数:name是给信号灯指定一个名字。oflag的值为O_CREAT,表示如果信号灯不存在,创建信号灯;为O_CREAT|O_EXCL,如果信号灯不存在报错。后面两个参数,只有新建信号灯时使用。mode为信号灯的权限(0644),value为信号灯的值。 7 返回值:成功时,返回信号灯的指针,错误返回SEM_FAILED 8 9 2.sem_close函数。 10 功能:关闭引用信号灯,信号灯引用计数减1。 11 头文件:#include <semaphore.h> 12 函数原型:int sem_close(sem_t * sem) 13 参数:sem为信号灯的指针 14 返回值:成功时,返回0,失败,-1 15 注:每个信号灯有一个引用计数器记录当前打开次数.关闭一个信号灯并没有将它从系统中删除,而是信号灯引用计数减1 16 17 18 3.sem_unlink函数 19 功能:信号灯引用计数为0时,从系统中删除信号灯。 20 头文件:#include <semaphore.h> 21 函数原型:int sem_close(const char *name) 22 参数:name为信号灯的外部名字 23 返回值:成功时,返回0,失败,-1 24 25 4.sem_wait/sem_trywait函数 26 功能:等待共享资源,信号灯值为0就睡眠,信号灯值大于0,就使用共享资源,信号灯值减1。sem_trywait当信号灯值为0时,不睡眠,报错。 27 头文件:#include <semaphore.h> 28 函数原型:int sem_wait(sem_t *sem),int sem_trywait(sem_t *sem) 29 参数:sem为信号灯指针 30 返回值:成功时,返回0,失败,-1 31 32 5.sem_getvalue函数 33 功能:获得信号灯的值 34 头文件:#include <semaphore.h> 35 函数原型:int sem_getvalue(sem_t *sem,int *valp) 36 参数:sem为信号灯指针,valp为信号灯的值 37 返回值:成功时,返回0,失败,-1 38 39 6.sem_post函数 40 功能:使用完共享资源后,信号灯值加1,唤醒其他睡眠的。 41 头文件:#include <semaphore.h> 42 函数原型:int sem_post(sem_t *sem) 43 参数:sem为信号灯指针 44 返回值:成功时,返回0,失败,-1
示例代码:
1 /*semopen_pth.c*/ 2 #include <stdio.h> 3 #include <semaphore.h> 4 #include <fcntl.h> 5 #include <pthread.h> 6 7 void print(); 8 void * thread_function(void *arg); 9 sem_t * sem; 10 11 int main(int argc,char * argv[]) 12 { 13 int n=0; 14 pthread_t tid; 15 if(argc != 2) 16 { 17 printf("Usage:%s name.\n",argv[0]); 18 exit(0); 19 } 20 //init semaphore 21 sem=sem_open(argv[1],O_CREAT,0644,3); 22 while(n++<5) 23 { 24 if((pthread_create(&tid,NULL,thread_function,NULL))!=0) 25 { 26 printf("can't create pthread.\n"); 27 exit(0); 28 } 29 } 30 pthread_join(tid,NULL); //主线程需要等会其它线程 31 sem_close(sem); 32 sem_unlink(argv[1]); 33 return 0; 34 } 35 36 void * thread_function(void *arg) 37 { 38 sem_wait(sem); 39 print(); 40 sleep(1); //因为共享段执行过快,不能达到同步效果,所以需要睡眠 41 sem_post(sem); 42 printf("finish, pthread_id is %d\n",pthread_self()); 43 } 44 45 void print() 46 { 47 int value; 48 printf("pthread_id is %d, get the resource\n",pthread_self()); 49 sem_getvalue(sem,&value); 50 printf("now,the semaphore value is %d\n",value); 51 }
编译并执行:
1 root@linux:/mnt/hgfs/C_libary# gcc -lpthread -o semopen_pth semopen_pth.c 2 semopen_pth.c: In function ‘main’: 3 semopen_pth.c:17: warning: incompatible implicit declaration of built-in function ‘exit’ 4 semopen_pth.c:26: warning: incompatible implicit declaration of built-in function ‘exit’ 5 semopen_pth.c: In function ‘thread_function’: 6 semopen_pth.c:41: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘pthread_t’ 7 semopen_pth.c: In function ‘print’: 8 semopen_pth.c:47: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘pthread_t’ 9 root@linux:/mnt/hgfs/C_libary# 10 注:产生了一些警告,先不管这些,看看是否能运行 11 root@linux:/mnt/hgfs/C_libary# ./semopen_pth sem 12 pthread_id is -1217336464, get the resource 13 now,the semaphore value is 2 14 pthread_id is -1225729168, get the resource 15 now,the semaphore value is 1 16 pthread_id is -1234121872, get the resource 17 now,the semaphore value is 0 18 finish, pthread_id is -1217336464 19 finish, pthread_id is -1225729168 20 finish, pthread_id is -1234121872 21 pthread_id is -1242514576, get the resource 22 now,the semaphore value is 2 23 pthread_id is -1250907280, get the resource 24 now,the semaphore value is 1 25 finish, pthread_id is -1242514576 26 finish, pthread_id is -1250907280 27 root@linux:/mnt/hgfs/C_libary#
有名信号灯同步多进程:
unix网络编程第二卷,如是说不同进程(不管是否彼此有无亲缘关系),他们都可以访问同一个信号灯,只是需要在sem_open的时候传入的名字是一样就行。在有亲缘关系时,Posix中的fork如是描述,在父进程中打开的任何信号灯,仍应在子进程中打开。
示例代码:
1 /*semopen_pro.c*/ 2 #include <stdio.h> 3 #include <semaphore.h> 4 #include <fcntl.h> 5 #include <unistd.h> 6 #include <sys/types.h> 7 #include <sys/wait.h> 8 9 void print(); 10 sem_t * sem; 11 12 int main(int argc,char * argv[]) 13 { 14 int n=0,j; 15 pid_t pid; 16 17 if(argc != 2) 18 { 19 printf("Usage:%s name.\n",argv[0]); 20 exit(0); 21 } 22 23 //该信号灯不会因为不同进程而不同。 24 sem=sem_open(argv[1],O_CREAT,0644,3); 25 while(n++<5) 26 { 27 pid = fork(); 28 if(pid == 0) 29 { 30 sem_wait(sem); 31 print(); 32 sleep(1); 33 sem_post(sem); 34 printf("finish,the pid is %d\n",getpid()); 35 exit(0); 36 } 37 } 38 39 j=0; 40 41 //等待所有子进程退出 42 while(j++<5) 43 wait(NULL); 44 sem_close(sem); 45 sem_unlink(argv[1]); 46 return 0; 47 } 48 49 void print() 50 { 51 int value; 52 printf("pid is %d, get the resource\n",getpid()); 53 sem_getvalue(sem,&value); 54 printf("now,the semaphore value is %d\n",value); 55 }
编译并执行:
1 root@linux:/mnt/hgfs/C_libary# gcc -o semopen_pro semopen_pro.c 2 semopen_pro.c: In function ‘main’: 3 semopen_pro.c:19: warning: incompatible implicit declaration of built-in function ‘exit’ 4 semopen_pro.c:34: warning: incompatible implicit declaration of built-in function ‘exit’ 5 /tmp/ccUECdL7.o: In function `main': 6 semopen_pro.c:(.text+0x5d): undefined reference to `sem_open' 7 semopen_pro.c:(.text+0x81): undefined reference to `sem_wait' 8 semopen_pro.c:(.text+0x9f): undefined reference to `sem_post' 9 semopen_pro.c:(.text+0x107): undefined reference to `sem_close' 10 semopen_pro.c:(.text+0x117): undefined reference to `sem_unlink' 11 /tmp/ccUECdL7.o: In function `print': 12 semopen_pro.c:(.text+0x14e): undefined reference to `sem_getvalue' 13 collect2: ld returned 1 exit status 14 注:sem_XXX函数不是标准库函数,链接时需要指定库-lrt or -pthread. 15 root@linux:/mnt/hgfs/C_libary# gcc -lrt -o semopen_pro semopen_pro.c 16 semopen_pro.c: In function ‘main’: 17 semopen_pro.c:19: warning: incompatible implicit declaration of built-in function ‘exit’ 18 semopen_pro.c:34: warning: incompatible implicit declaration of built-in function ‘exit’ 19 root@linux:/mnt/hgfs/C_libary# ./semopen_pro sem 20 pid is 5262, get the resource 21 now,the semaphore value is 2 22 pid is 5263, get the resource 23 now,the semaphore value is 1 24 pid is 5264, get the resource 25 now,the semaphore value is 0 26 finish,the pid is 5262 27 pid is 5265, get the resource 28 now,the semaphore value is 0 29 finish,the pid is 5263 30 pid is 5266, get the resource 31 now,the semaphore value is 0 32 finish,the pid is 5264 33 finish,the pid is 5265 34 finish,the pid is 5266 35 root@linux:/mnt/hgfs/C_libary#
基于内存的信号灯同步多线程:
1 sem_init() 2 功能:初始化信号灯。 3 头文件:#include <semaphore.h> 4 函数原型:int sem_open(sem_t * sem,int shared,unsigned int value); 5 参数:sem为信号灯指针,shared是指同步多线程还是多进程(0:多线程,其他:多进程),value为信号量值 6 返回值:成功时,返回0,失败时,返回-1 7 8 sem_destroy() 9 功能:关闭信号 10 头文件:#include <semaphore.h> 11 函数原型:int sem_destroy(sem_t * sem) 12 参数:sem为信号灯的指针 13 返回值:成功时,返回0,失败,-1
示例代码:
1 /*seminit_pth*/ 2 #include <stdio.h> 3 #include <semaphore.h> 4 #include <fcntl.h> 5 #include <pthread.h> 6 7 void print(); 8 void * thread_function(void *arg); 9 sem_t sem; 10 11 int main(int argc,char * argv[]) 12 { 13 int n=0; 14 pthread_t tid; 15 //init semaphore 16 sem_init(&sem,0,3); 17 while(n++<5) 18 { 19 if((pthread_create(&tid,NULL,thread_function,NULL))!=0) 20 { 21 printf("can't create pthread.\n"); 22 exit(0); 23 } 24 } 25 pthread_join(tid,NULL); 26 sem_destroy(&sem); 27 return 0; 28 } 29 30 void * thread_function(void *arg) 31 { 32 sem_wait(&sem); 33 print(); 34 sleep(1); // 35 sem_post(&sem); 36 printf("finish, pthread_id is %d\n",pthread_self()); 37 } 38 39 void print() 40 { 41 int value; 42 printf("pthread_id is %d, get the resource\n",pthread_self()); 43 sem_getvalue(&sem,&value); 44 printf("now,the semaphore value is %d\n",value); 45 }
编译运行:
1 root@linux:/mnt/hgfs/C_libary# gcc -lrt -o seminit_pth seminit_pth.c 2 seminit_pth.c: In function ‘main’: 3 seminit_pth.c:21: warning: incompatible implicit declaration of built-in function ‘exit’ 4 seminit_pth.c: In function ‘thread_function’: 5 seminit_pth.c:35: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘pthread_t’ 6 seminit_pth.c: In function ‘print’: 7 seminit_pth.c:41: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘pthread_t’ 8 root@linux:/mnt/hgfs/C_libary# 9 root@linux:/mnt/hgfs/C_libary# ./seminit_pth 10 pthread_id is -1224959120, get the resource 11 now,the semaphore value is 2 12 pthread_id is -1233351824, get the resource 13 now,the semaphore value is 1 14 pthread_id is -1241744528, get the resource 15 now,the semaphore value is 0 16 finish, pthread_id is -1224959120 17 finish, pthread_id is -1233351824 18 finish, pthread_id is -1241744528 19 pthread_id is -1250137232, get the resource 20 now,the semaphore value is 2 21 pthread_id is -1216566416, get the resource 22 now,the semaphore value is 1 23 finish, pthread_id is -1250137232 24 finish, pthread_id is -1216566416 25 root@linux:/mnt/hgfs/C_libary#