linux system v信号量,Linux中的System V信号量

在进程同步,并发运行时,保证按序地访问共享资源是十分重要的。因此引入了临界区的概念,一次只能有一个线程进入临界区完成他的指令。而信号量(semaphore)的作用,类似于一个交通信号灯,它负责进程协作,因此信号量又称为信号灯。

在Linux系统中,它提供两种信号量:

内核信号量,由内核控制路径使用

用户态进程使用的信号量,这种信号量有两种接口,POSIX信号量和SYSTEM V信号量。

信号量的本质是一个计数器。一个较为常见的用法,是为每个资源都会分配一个信号量。记信号量为S,除了初始化之外,有两个标准原子操作:wait()和signal()。

System V信号量接口

semget

创建一个新信号量或取得一个已有信号量

int semget(key_t key, int num_sems, int sem_flags);

key是一个整数值(唯一非零),可以理解成是信号量的标识符。

num_sems指定了需要的信号量数目,通常为1。

sem_flags是一组标志,当创建一个新的信号量时,设定权限与值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,即使给出的键是一个已有信号量的键,也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。

函数成功返回一个相应信号标识符(非零),失败返回-1。

semctl

直接控制信号量信息

int semctl(int sem_id, int sem_num, int command, ...);

第二个参数是操作信号在信号集中的编号,第一个信号的编号是0。

第三个参数command通常是下面两个值中的其中一个:

SETVAL:用来把信号量初始化为一个已知的值。

IPC_RMID:用于删除一个已经无需继续使用的信号量标识符。

如果有第四个参数,它通常是一个union semum结构,定义如下:

union semun

{

int val;

struct semid_ds *buf;

unsigned short *arry;

};

semop

改变信号量的值

int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);

sem_id是由semget返回的信号量标识符,sembuf结构的定义如下:

struct sembuf{

short sem_num;//除非使用一组信号量,否则为0

short sem_op;//信号量在一次操作中需要改变的数据,-1即P(等待)操作,+1即V(发送信号)操作。

short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号,并在进程没有释放该信号量而终止时,操作系统释放信号量

};

进程同步实例

无信号量实例

#include

#include

#include

int main()

{

pid_t pid;

pid = fork();

srand(pid);

if(pid > 0) // parent process

{

char a = 'A'; // char to print

for(int i = 0; i < 10; ++i)

{

printf("%c", a);

fflush(stdout); // flush stdout buffer

sleep(1);

printf("%c", a);

fflush(stdout);

sleep(1);

}

}

else // child process

{

char b = 'B';

for(int i = 0; i < 10; ++i)

{

printf("%c", b);

fflush(stdout);

sleep(1);

printf("%c", b);

fflush(stdout);

sleep(1);

}

}

printf("n%d - finishedn", getpid());

sleep(3);

return 0;

}

运行结果

7ff4e4e80bb90488175a494150e2e96a.png

有信号量实例

#include

#include

#include

#include

#include

#include

#include

#define SEMKEY 0x00002222 // set a key for semaphore

union semun // union for semaphore

{

int val;

struct semid_ds *buf;

unsigned short *array;

};

struct sembuf p = { 0, -1, SEM_UNDO};

struct sembuf v = { 0, +1, SEM_UNDO};

int main()

{

int sem_id = semget(SEMKEY, 1, 0666 | IPC_CREAT); // get semaphore

union semun sem_union;

sem_union.val = 1;

if(semctl(sem_id, 0, SETVAL, sem_union) < 0)

{

perror("semctl error");

return -1;

}

int pid;

pid = fork();

srand(pid);

if(pid > 0) // parent process

{

char a = 'A'; // char to print

for(int i = 0; i < 10; ++i)

{

if(semop(sem_id, &p, 1) < 0) // P operation

{

perror("semop p error");

return -1;

}

printf("%c", a);

fflush(stdout); // flush stdout buffer

sleep(1);

printf("%c", a);

fflush(stdout);

if(semop(sem_id, &v, 1) < 0) // V operation

{

perror("semop v error");

return -1;

}

sleep(1);

}

}

else // child process

{

char b = 'B'; // char to print

for(int i = 0; i < 10; ++i)

{

if(semop(sem_id, &p, 1) < 0) // P operation

{

perror("semop p error");

return -1;

}

printf("%c", b);

fflush(stdout); // flush stdout buffer

sleep(1);

printf("%c", b);

fflush(stdout);

if(semop(sem_id, &v, 1) < 0) // V operation

{

perror("semop v error");

return -1;

}

sleep(1);

}

}

printf("n%d - finishedn", getpid());

sleep(3);

if (pid > 0)

{

system("ipcrm -S 0x00002222");

}

return 0;

}

运行结果

a5a5a7dd80262a2e3f29e7ac08f79990.png

因为设定信号量的关系,一个线程在临界区内一定会执行两次print()操作,所以A或B一定成对出现。

程序员灯塔

转载请注明原文链接:Linux中的System V信号量

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值