POSIX信号量
POSIX信号量分为两种,分别是POSIX无名信号量和POSIX有名信号量。这两种信号量比之前的system-V的信号量机制更加简洁。
1、POSIX有名信号量
- 这种又名信号量的名字类似于
/somexxxxx
这样的字符串,前面需要一个正斜杠,这样的信号量其实是一个特殊的文件,创建成功后会被放置在系统的一个特殊虚拟文件系统/dev/shm
中。不同的进程只要约定好一个相同的名字,就可以通过这种有名信号量来相互协调。 - 有名信号量和system-V中的信号量都是属于系统资源,在进程推出后他们不会自动消失,需要用户手动删除并释放资源。
创建打开一个POSIX有名信号量:
对POSIX信号量进程PV操作
- system-V的信号量申请和释放的个数可以超过1个资源。对于POSIX来说,每次申请和释放的资源数都是1。其中调用sem_wait()在资源为0时会阻塞等待,如果不想等待,可以用
sem_trywait()
来代替
关闭和删除POSIX有名信号量
练习:
1、使用POSIX有名信号量实现进程间的内存共享操作
//send.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 , 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;
}
//recv.v
#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>
#include "unistd.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、POSIX无名信号量
如果我们要解决的问题是一个线程内部的同步互斥问题,那么我们可以不需要使用POSIX有名信号量,可以使用无名信号量来达到目的。
初始化和销毁无名信号量
- 无名信号量一般都用在进程内的线程间,因此pshared一般都为0。
- 当此信号用在进程间时,必须将他定义在每个进程都能访问的位置–如共享内存当中
练习:1、使用POSIX无名信号量实现进程内的内存共享操作
#include "stdio.h"
#include <semaphore.h>
#include "unistd.h"
#include "stdlib.h"
#include "pthread.h"
//定义线程间的共享资源
sem_t sem;
//定义线程间的共享内存
char *mem_map = NULL;
void* func(void * arg)
{
char *msg = (char *)arg;
while(1)
{
//等待资源
sem_wait(&sem);
printf("线程收到资源为:%s\n", mem_map);
sem_post(&sem);
sleep(3);
}
}
int main()
{
//初始化共享内存
mem_map = malloc(32);
//初始化无名信号量 0 表示在进程间通信 1表示初始化资源为1
if(sem_init(&sem, 0 ,1))
{
printf("sem error\n");
return -1;
}
//创建线程
pthread_t pid;
pthread_create(&pid, NULL, func, NULL);
while(1)
{
sem_wait(&sem);
fgets(mem_map, 32, stdin);
sem_post(&sem);
sleep(3);
}
}
无名信号量是在进程内部线程之间进行同步的,因此不需要手动销毁