一、信号量(POSIX)的分类
POSIX 有名信号量:可以在进程之间使用(属于系统级别的资源,基本可以替代IPC中的信号量) POSIX 无名信号量:只能在进程的内部,线程之间互相使用(使用同一个内存区)
二、POSIX 有名信号量
1、有名信号量的相关简介
(1)名字:由类似“/somename”这样的字符串组成此时信号量的实质是一个特殊的文件
(2)有名信号量创建成功之后将会被放置在系统的一个特殊的虚拟文件系统/dev/shm之中
(3)不同的进程只有约定号一个相同的名字,就可以通过这种有名信号量来相互协调。
(4)有名信号量跟 system-V 的信号量都是系统范畴的,在进程退出之后 他们并不会自动消失,而需要手工删除并释放资源。
3、API
(1)sem_open(创建、打开一个POSIX有名信号量)
(2)sem_wait/sem_post(对POSIX有名信号量进行P、V操作)
(3)sem_close/sem_unlink(关闭、删除POSIX有名信号量)
(4)解决阻塞
不像 system-V 的信号量可以申请或者释放超过 1 个资源,对于 POSIX 信号量而言, 每次申请和释放的资源数都是 1。其中调用 sem_wait( )在资源为 0 时会导致阻塞,如果 不想阻塞等待,可以使用 sem_trywait( )来替代。
4、有名信号量使用步骤
(1)使用 sem_open( )来创建或者打开一个有名信号量。
(2)使用 sem_wait( )和 sem_post( )来分别进行 P 操作和 V 操作。
(3)使用 sem_close( )来关闭他。
(4)使用 sem_unlink( )来删除他,并释放系统资源
5、代码(内存共享+有名信号量)
(1)recv_sem_name.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
char * shm_init( void )
{
// 获取key值
int key = ftok("./" , 'X');
// 获取SHM 的ID
int shm_id = shmget(key , 4096 , IPC_CREAT | 0644 );
if (-1 == shm_id )
{
perror("shmget id error");
exit(1); // 直接结束程序(退出进程)
}
// 映射共享内存
char * shm_map = shmat(shm_id , NULL , 0 );
if ((void *) -1 == shm_map)
{
perror("shm map error");
exit(1); // 直接结束程序(退出进程)
}
return shm_map ;
}
int main(int argc, char const *argv[])
{
// 先搞定共享内存并初始化
char * shm_map = shm_init();
// 有名信号量
// 使用 sem_open( )来创建或者打开一个有名信号量。
sem_t * fd_sem = sem_open("/my_sem_name", O_CREAT , 0644 , 0 ); // 创建一个新的有名信号量并初始化资源为1
while(1)
{
// 申请一个资源
printf("等待申请资源中!!\n");
sem_wait( fd_sem );
printf("成功申请到资源!!!\n");
// 输出共享内存的内容
printf ("收到消息:%s\n" , shm_map);
sleep(2);
// 释放1个资源
printf("释放资源!!\n");
sem_post(fd_sem);
}
return 0;
}
(2)send_sem_name
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
char * shm_init( void )
{
// 获取key值
int key = ftok("./" , 'X');
// 获取SHM 的ID
int shm_id = shmget(key , 4096 , IPC_CREAT | 0644 );
if (-1 == shm_id )
{
perror("shmget id error");
exit(1); // 直接结束程序(退出进程)
}
// 映射共享内存
char * shm_map = shmat(shm_id , NULL , 0 );
if ((void *) -1 == shm_map)
{
perror("shm map error");
exit(1); // 直接结束程序(退出进程)
}
return shm_map ;
}
int main(int argc, char const *argv[])
{
// 先搞定共享内存并初始化
char * shm_map = shm_init();
// 有名信号量
// 使用 sem_open( )来创建或者打开一个有名信号量。
sem_t * fd_sem = sem_open("/my_sem_name", O_CREAT , 0644 , 1); // 创建一个新的有名信号量并初始化资源为1
while(1)
{
// 申请一个资源
printf("等待申请资源中!!\n");
sem_wait( fd_sem );
printf("成功申请到资源!!!\n 请输入消息:\n");
// 写入信息到共享内存中
fgets(shm_map , 4096 , stdin);
// 释放1个资源
printf("释放资源!!\n");
sem_post(fd_sem);
}
// 程序退出时应当释放信号量资源
return 0;
}