Posix标准有名信号量和无名信号量的使用

13 篇文章 4 订阅

一、有名信号量  
                    
      在文件系统中有一个名字 即有一个对应的inode节点 ,但是信号量的内容(值)确实存在于内核中 ,一般可以用于任意线程或进程间。
                    
有名信号量的操作一般有: 
          sem_open
          sem_wait/sem_post
          sem_close

          sem_unlink

sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
 
name : 要创建或打开的POSIX有名信号量在文件系统中的路径名 
要求是以'/'开头的路径名(路径名中只能有1个/)
如: "/test.sem"
 也就是说你的有名信号量必须在根目录下面
                                    
oflag: 打开标志 
(1) 打开:  0 
(2) 创建:  O_CREAT 
                                    
如果你是打开则只需要两个参数 如果是创建则带四个参数 
mode : 创建权限位  有两种方式指定 
(1)S_IRUSR S_IWUSR S_IXUSR 
(2)0664 

                    
value: 制定创建的有名信号量的初始值          
返回值: 
成功返回一个sem_t的一个指针 指向POSIX有名信号量 
失败返回SEM_FAILED 并且errno被设置

int sem_wait(sem_t *sem);
    
如果P操作获取不了资源
此函数会阻塞死等 


返回值:
返回0 表示成功获取了该信号量 
返回-1 表示出错 并且errno被设置

int sem_post(sem_t *sem);       
函数功能: V操作  用来释放sem指定的POSIX信号量

int sem_close(sem_t *sem);
                           
sem_close 用来关闭一个POSIX有名信号量 


int sem_unlink(const char *name);
                           
sem_unlink用来删除一个POSIX有名信号量
                    
参数: 要删除的POSIX的有名信号量的路径名

实例1:父子进程间将共享内存中的值各加10万次

/**************************************************************
  > File Name: sendShmget.c
  > Author: LuoLiang
  > Mail: 1204553475@qq.com 
  > Created Time: 2022年02月23日 星期三 03时16分19秒
 **************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <sys/wait.h>

#define PATHNAME "./test.ftok"
#define SEMPATH "/test1.sem"

int main(int argc, char **argv)
{
	key_t key;
	sem_t *semp = NULL;
	int shmid;
	int proc_id = 1;
	size_t size = 4096;
	int *shmp = NULL;
	pid_t pid;
	int n = 0;

	key = ftok(PATHNAME, proc_id);
	if (key < 0)
	{
		perror("ftok()");
		exit(1);
	}
	
	shmid = shmget(key, size, IPC_CREAT | 0666);
	if (shmid < 0)
	{
		perror("shmget()");
		exit(1);
	}
	
	shmp = shmat(shmid, NULL, 0);
	if (shmp == NULL)
	{
		perror("shmat()");
		exit(1);
	}
	
	*shmp = 0;
	semp = sem_open(SEMPATH, O_CREAT, 0664, 1);
	if (semp == SEM_FAILED)
	{
		perror("sem_open()");
		exit(1);
	}

	pid = fork();
	if (pid < 0)
	{
		perror("fork()");
		exit(1);
	}
	if (pid == 0)
	{
		while (n < 100000)
		{
			sem_wait(semp);
			(*shmp)++;
			sem_post(semp);
			n++;
		}
		exit(0);
	}
	while (n < 100000)
	{
		sem_wait(semp);
		(*shmp)++;
		sem_post(semp);
		n++;
	}

	wait(NULL);
	printf("%d\n",*shmp);

	sem_close(semp);
	sem_unlink(SEMPATH);
	shmdt(shmp);
    exit(0);
}

                                        
二、 无名信号量
                
        没有名字无名信号量存在于内存中,一般用于线程间 和 有亲缘关系的进程间 。
                    
无名信号量的操作一般有:
         sem_init 
         sem_wait/sem_post
         sem_destory

函数原型: 

int sem_init(sem_t *sem, int pshared, unsigned int value);


sem:  指向要初始化的无名信号量  
一般我们会先定义或者分配一个无名信号量 sem_t 

pshared: 该无名信号量的共享方式  
0:进程内部的线程共享   
1:不同进程间的共享  
value : 指定该无名信号量的初始值

int sem_wait(sem_t *sem);
    
如果P操作获取不了资源
此函数会阻塞死等 


返回值:
返回0 表示成功获取了该信号量 
返回-1 表示出错 并且errno被设置

int sem_post(sem_t *sem);       
函数功能: V操作  用来释放sem指定的POSIX信号量

int sem_destroy(sem_t *sem);
sem_destory用来销毁一个POSIX的无名信号量

实例1:求共享内存中的值两个线程各加10万次

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <pthread.h>
#include <sys/wait.h>

#define PATHNAME "log"
#define TIDSIZE 3

sem_t *semp;
int *shmp = NULL;

void *pthread_handler(void *args)
{
	int n = 100000LL;		
	sem_wait(semp);
	while (n--)
	{
		(*shmp)++;
	}
	sem_post(semp);

	pthread_exit(NULL);
}

int main(int argc, char **argv)
{
	key_t key;
	int shmid;
	int proc_id = 1;
	size_t size = 4096;
	pthread_t tid[TIDSIZE];

	key = ftok(PATHNAME, proc_id);
	if (key < 0)
	{
		perror("ftok()");
		exit(1);
	}
	
	shmid = shmget(key, size, IPC_CREAT | 0666);
	if (shmid < 0)
	{
		perror("shmget()");
		exit(1);
	}
	
	shmp = shmat(shmid, NULL, 0);
	if (shmp == NULL)
	{
		perror("shmat()");
		exit(1);
	}
	
	*shmp = 0;

	semp = (sem_t *)malloc(sizeof(sem_t));
	
	if (sem_init(semp, 0, 1) < 0)
	{
		perror("sem_init()");
		exit(1);
	}
	
	for (int i = 0; i < 3; i++)
	{
		pthread_create(tid+i, NULL, pthread_handler, NULL);
	}
	
	for (int i = 0; i < 3; i++)
	{
		pthread_join(tid[i], NULL);	
	}

	printf("%d\n",*shmp);
	
	sem_destroy(semp);
	shmdt(shmp);
    exit(0);
}

实例二:父子进程间将共享内存中的值各加10万次

注意:在具有亲缘关系的进程中信号量也必须放在共享内存你,在fork前分配的空间也不能使用,所以要借用mmap函数来映射一块共享空间,不是很方便,尽量只在线程中使用无名信号量。


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/wait.h>

#define PATHNAME "/tmp/out"


int main(int argc, char **argv)
{
	sem_t *semp = NULL;
	key_t key;
	int shmid;
	int proc_id = 1;
	size_t size = 4096;
	int *shmp = NULL;
	pid_t pid;
	int n = 100000LL;

	key = ftok(PATHNAME, proc_id);
	if (key < 0)
	{
		perror("ftok()");
		exit(1);
	}
	
	shmid = shmget(key, size, IPC_CREAT | 0666);
	if (shmid < 0)
	{
		perror("shmget()");
		exit(1);
	}
	
	shmp = shmat(shmid, NULL, 0);
	if (shmp == NULL)
	{
		perror("shmat()");
		exit(1);
	}
	
	*shmp = 0;
	semp = (sem_t *)mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
	if (semp == NULL)
	{
		perror("mmap()");
		exit(1);
	}

	if (sem_init(semp, 1, 1) < 0)
	{
		perror("sem_init()");
		exit(1);
	}

	pid = fork();
	if (pid < 0)
	{
		perror("fork()");
		exit(1);
	}
	if (pid == 0)
	{
		while (n--)
		{
			sem_wait(semp);
			(*shmp)++;
			sem_post(semp);
		}
		exit(0);
	}

	while (n--)
	{
		sem_wait(semp);
		(*shmp)++;
		sem_post(semp);
	}

	wait(NULL);
	printf("%d\n",*shmp);

	sem_destroy(semp);
	shmdt(shmp);
	munmap(semp, sizeof(sem_t));
    exit(0);
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值