📄 sem.c
字号:
/**********************************************************************
*FileName: sem.c
*
*Perpose : 通过信号量来同步进程,让两个进程分别输出aaa bbb.
* 直到用户按下Ctrl+C.这个程序的功能类似于Linus在
* 开始写Linux时写的第一个版本.不过Linux是在保护模
* 式下,通过时钟中断来实现的.这个程序只是通过操作系
* 统提供的system call来实现.所以很简单!!!
*
*Author : 刘海洋
*Version : 2008-11-08 第一版
*
*Addition: 这里创建了一个信号量集,这个信号量集包含了一个信号量
* 并且信号量的最大值为1, 所以这里的信号量可以理解为互斥体
**********************************************************************/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#define SEMPERM 0600 /* 八进制,所以前面的0不能省略 */
typedef union _semun
{
int val;
struct semid_ds *buf;
ushort *array;
}semun;
/*
===============
初始化信号量
===============
*/
int initsem(key_t semkey)
{
int status = 0;
int semid;
/* 试着创建一个信号量 */
semid = semget(semkey, 1, SEMPERM | IPC_CREAT | IPC_EXCL);
if (semid == -1) /* 创建失败 */
{
if (errno == EEXIST) /* 如果存在,试着获取它 */
{
semid = semget(semkey, 1, 0);
}
}
else /* 创建成功,则给信号量赋初值 */
{
semun arg;
arg.val = 1;
status == semctl(semid, 0, SETVAL, arg);
}
if (semid == -1 || status == -1)
{
perror("init semaphore failed!\n");
exit(-1);
}
return semid;
}
/*
=============
信号量P操作
=============
*/
int p(int semid)
{
struct sembuf p_buf;
p_buf.sem_num = 0;
p_buf.sem_op = -1;
p_buf.sem_flg = SEM_UNDO;
if (semop(semid, &p_buf, 1) == -1)
{
perror("semaphore p operation failed\n");
exit(-1);
}
return 0;
}
/*
=============
信号量v操作
=============
*/
int v(int semid)
{
struct sembuf p_buf;
p_buf.sem_num = 0;
p_buf.sem_op = 1;
p_buf.sem_flg = SEM_UNDO;
if (semop(semid, &p_buf, 1) == -1)
{
perror("semaphore v operation failed\n");
exit(-1);
}
return 0;
}
/*
=============
删除信号量
=============
*/
int rmsem(int semid)
{
semun sem;
sem.val = 0;
if (semctl(semid, 0, IPC_RMID, sem) == -1)
{
perror("remove semaphore failed\n");
exit(-1);
}
return 0;
}
/*
========================
通过信号量同步循环输出
========================
*/
int printbysem(int semid, char *str)
{
while (1)
{
p(semid); /* Note */
printf("%s", str);
sleep(1);
v(semid); /* Note */
sleep(1);
}
return 0;
}
/*
==================================
在sigint中删除信号量时,需要指定ID
==================================
*/
int g_sem_id = 0;
/*
==============
中断信号处理
==============
*/
void sigint(int signo)
{
rmsem(g_sem_id);
printf("\n");
exit(0);
}
/*
===============
Program Entry
===============
*/
int main(void)
{
key_t sem_key = 0x200;
int semid;
setbuf(stdout, NULL); /* 设置输入输出缓冲为无缓冲 */
switch (fork())
{
case -1: /* error */
perror("create new process failed!\n");
break;
case 0: /* child process */
semid = initsem(sem_key);
printbysem(semid, "aaa");
break;
default: /* perant process */
g_sem_id = semid = initsem(sem_key);
signal(SIGINT, sigint); /* 只有父进程注册信号处理函数 */
printbysem(semid, "bbb");
break;
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -