一、有名信号量
1、POSIX有名信号量
有名信号量创建成功之后会在系统中的一个特殊的虚拟文件系统 /dev/shm,不同的进程间约好同一名,即可通过这种有名信号量来相互协调。还有有名信号量和system-V的信号量一样,进程退出不会自动消失,需要人手删除并释放资源
使用步骤:
1.1 使用sem_open()创建或者打开一个有名信号量
1.2 使用sem_wait()和sem_post()来分别进行p操作和v操作
1.3 使用sem_close()关闭信号量
1.4 使用sem_unlink()删除信号量,释放系统资源
2、API函数原型
不想system-V的信号量可以申请或者释放超过1个资源,对于POSIX信号量而言,每次只能申请或释放资源数1,当调用sem_wait()时,资源为0会阻塞,如果不想阻塞可以使用sem_trywait()l来代替
3.有名信号量例子
两个进程间通过使用有名信号量访问功效内存通信,semname1.c往共享内存写数据,semname2.c读取功效内存数据
semname1.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>
#define SHMSIZE 1024 //共享内存大小
#define SEMNAME "test" //有名信号量名字
int main(int argc, void *argv[])
{
key_t key = ftok("./", 100); //生成键值
int id = shmget(key, SHMSIZE, IPC_CREAT|0666); //获取功效内存id
char *shmaddr = shmat(id, NULL, 0); //申请共享内存资源
sem_t *s;
s = sem_open(SEMNAME, O_CREAT, 0777, 0); //创建有名信号量
while(1)
{
fgets(shmaddr, SHMSIZE, stdin);
sem_post(s); //释放有名信号量,V操作
if(!strncmp(shmaddr, "quit", 4) ) //输入“quit”退出while
break;
}
sem_close(s); //关闭有名信号量
sem_unlink(SEMNAME); //删除有名信号量
exit(0);
}
semname2.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>
#define SHMSIZE 1024 //共享内存大小
#define SEMNAME "test" //有名信号量名字
int main(int argc, void *argv[])
{
key_t key = ftok("./", 100); //生成键值
int id = shmget(key, SHMSIZE, IPC_CREAT|0666); //获取功效内存id
char *shmaddr = shmat(id, NULL, 0); //申请共享内存资源
sem_t *s;
s = sem_open(SEMNAME, O_CREAT, 0777, 0); //创建或打开有名信号量
while(1)
{
sem_wait(s); //申请有名信号量,P操作
if(!strncmp(shmaddr, "quit", 4) ) //输入“quit”退出while
break;
printf("receive:%s\n", shmaddr);
}
sem_close(s); //关闭有名信号量
sem_unlink(SEMNAME); //删除有名信号量
exit(0);
}
二、无名信号量(匿名信号量)
1、POSIX无名信号量
如果我们要解决进程内部的同步互斥,不需要使用有名信号量,因为同一进程里的线程内存是共享,基于内存的(不在任何文件系统内部)无名信号量来达到目的。
有关函数如下所示:
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_post(sem_t *sem); //释放信号量
int sem_wait(sem_t *sem); //等待信号量
int sem_trywait(sem_t *sem); //不阻塞等待信号量
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); //设置超时等待信号量
int sem_destroy(sem_t *sem);
使用无名信号量步骤:
1.1在线程能访问到的区域定义这种变量(如全局变量),类型sem_t
1.2任何线程使用之前都要用sem_init()初始化
1.3 使用sem_wait()、sem_tywait()和sem_post()来分别进行P/V操作
1.4 不在需要时,使用sem_destroy()来销毁
无名信号量API函数原型
sem_wait()he sem_post()跟POSIX有名信号量一样。
2.无名信号量例子
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <pthread.h>
#define SIZE 1024 //内存大小
char buf[SIZE] = {0};
sem_t space, data;
void *RoutineRead(void *arg)
{
char *bufv = (char *)arg;
while(1)
{
sem_wait(&data); //申请无名信号量data资源,P操作
if(!strncmp(bufv, "quit", 4) ) //输入“quit”退出while
break;
printf("len:%d receive:%s\n", strlen(bufv), bufv);
sem_post(&space); //释放无名信号量space资源,V操作
}
}
int main(int argc, void *argv[])
{
sem_init(&space, 0, 1); //初始化无名信号量,参数2:0代表线程,非0代表非线性,参数3:初始化值为1
sem_init(&data, 0, 0);
pthread_t tid1;
pthread_create(&tid1, NULL, RoutineRead, (void *)buf);
while(1)
{
sem_wait(&space); //申请无名信号量space资源,P操作
memset(buf, 0, sizeof(buf));
fgets(buf, SIZE, stdin);
sem_post(&data); //释放无名信号量data资源,V操作
if(!strncmp(buf, "quit", 4) ) //输入“quit”退出while
break;
}
pthread_join(tid1, NULL); //阻塞等待子线程tid1退出
sem_destroy(&data); //销毁无名信号量
sem_destroy(&space);
exit(0);
}