IPC,Inter-Process Communication,进程间通信
ipcs : 查看当前系统的IPC机制使用情况

IPC进程间通信机制的料不多,信号量是一个比较难得点,但是要根据实际项目的场景进行分析,纸上谈兵是没有意义的。

通过种子文件获取KEY_L的值

如果各个进程都需要获取相同的IPC对象的ID,因此需要相同的KEY_L,也就是IPC秘钥,可以通过ftok函数来获取相同的key,使用方法很简单

  • 在目录下建立一个种子文件,注意不能删除这个文件
  • 所有的进程都调用ftok,第一个参数就是这个文件的路径和名字,第二个参数调相同的值,不为0即可

信号量的小工具分享

  • 分享一个信号量小工具,包括了信号量的所有操作
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>

union semun {
	int              val;    // Value for SETVAL 
	struct semid_ds *buf;    // Buffer for IPC_STAT, IPC_SET 
	unsigned short  *array;  // Array for GETALL, SETALL
	struct seminfo  *__buf;  // Buffer for IPC_INFO
};

/* 创建信号量 */
int sem_creat(key_t key)
{
	int semid;
	semid = semget(key, 1, 0666 | IPC_CREAT | IPC_EXCL);
	if (semid == -1)
	{
		perror("semget error");
		return -1;
	}
	return semid;
}

/* 删除信号量 */
int sem_delete(int semid)
{
	semctl(semid, 0, IPC_RMID, NULL);
	return 0;
}

/* 打开信号量 */
int sem_open(key_t key)
{
	int semid;
	semid = semget(key, 1, 0666);
	if (semid == -1)
	{
		perror("semget error");
		return -1;
	}
	return semid;
}

/* 设置信号量的值 */
int sem_setval(int semid, int val)
{
	int ret;
	union semun su;
	/* 表示资源的个数 */
	su.val = val;
	ret = semctl(semid, 0, SETVAL, su);
	if (ret == -1)
	{
		perror("semctl error");
		return -1;
	}
	return 0;
}

/* 获取信号量的值 */
int sem_getval(int semid)
{
	int val = 0;
	val = semctl(semid, 0, GETVAL, NULL);
	if (val == -1)
	{
		perror("semctl error");
		return -1;
	}
	printf("val : %d \n", val);
	return 0;
}

/* 信号量p操作 */
int sem_p(int semid)
{
	struct sembuf sp = {0, -1, 0};
	semop(semid, &sp, 1);
	return 0;
}

/* 信号量v操作 */
int sem_v(int semid)
{
	struct sembuf sv = {0, 1, 0};
	semop(semid, &sv, 1);
	return 0;
}
/* 获取信号量权限 */
int sem_getmode(int semid)
{
	int ret;
	int val;
	
	struct semid_ds buf;
	ret = semctl(semid, 0, IPC_STAT, &buf);
	if (ret == -1)
	{
		perror("semctl error");
		return -1;
	}
	val = buf.sem_perm.mode;
	printf("mode : 0%o \n",val);
	return val;
}

/* 设置信号量权限 */
int sem_setmode(int semid, int mode)
{
	int ret;
	
	struct semid_ds buf;
	buf.sem_perm.mode = mode;
	ret = semctl(semid, 0, IPC_SET, &buf);
	if (ret == -1)
	{
		perror("semctl error");
		return -1;
	}
	return 0;
}

void usage()
{
	fprintf(stderr,"semtool -c 创建信号量\n");
	fprintf(stderr,"semtool -d 删除信号量\n");
	fprintf(stderr,"semtool -p 信号量p操作\n");
	fprintf(stderr,"semtool -v 信号量v操作\n");
	fprintf(stderr,"semtool -s<val> 信号量设置初始值\n");
	fprintf(stderr,"semtool -g 获取信号量的值\n");
	fprintf(stderr,"semtool -f 打开权限\n");
	fprintf(stderr,"semtool -m<mode> 设置权限\n");
}

int main(int argc, char *argv[])
{
	int opt;
	opt = getopt(argc, argv, "cdpvs:gfm:");
	if (opt == -1)
	{
		usage();
		exit(EXIT_FAILURE);
	}
	
	key_t key;
	key = ftok(".",'s');
	int semid;
	
	switch (opt)
	{
		case 'c':
			semid = sem_creat(key);
			break;
		case 'd':
			semid = sem_open(key);
			sem_delete(semid);
			break;
		case 'p':
			semid = sem_open(key);
			sem_p(semid);
			sem_getval(semid);
			break;
		case 'v':
			semid = sem_open(key);
			sem_v(semid);
			sem_getval(semid);
			break;
		case 's':
			semid = sem_open(key);
			sem_setval(semid, atoi(optarg));
			sem_getval(semid);
			break;
		case 'g':
			semid = sem_open(key);
			sem_getval(semid);
			break;
		case 'f':
			semid = sem_open(key);
			sem_getmode(semid);
			break;
		case 'm':
			semid = sem_open(key);
			sem_setmode(semid, atoi(optarg));
			break;
		case '?':
			usage();
			break;
	}

	return 0;
}

可以使用这个小工具进行信号量的创建,使用,删除,pv操作,运行结果:


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

IPC小工具 上一篇
管道 下一篇