Linux下的进程间通信——信号量

一、什么是进程间通信

进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是共享内存区。但是,系统空间却是“公共场所”,所以内核显然可以提供这样的条件。除此以外,那就是双方都可以访问的外设了。在这个意义上,两个进程当然也可以通过磁盘上的普通文件交换信息,或者通过“注册表”或其它数据库中的某些表项和记录交换信息。广义上这也是进程间通信的手段,但是一般都不把这算作“进程间通信”。

二、信号量在进程间通信方式

信号(Signals )是Linux系统中使用的最古老的进程间通信的方法之一。 操作系统通过信号来通知进程系统中发生了某种预先规定好的事件(一组事件中的一个),它也是用户进程之间通信和同步的一种原始机制。一个键盘中断或者一个错误条件(比如进程试图访问它的 虚拟内存中不存在的位置等)都有可能产生一个信号。Shell也使用信号向它的子进程发送 作业控制信号。

1、临界资源
同一时刻只允许一个进程访问的资源叫临界资源。

2、临界区
访问临界资源的代码即是临界区。

3、原子操作
通过P、V操作来控制同步进程。

4、下面是几个常见的信号。

SIGHUP: 从 终端上发出的结束信号;

SIGINT: 来自键盘的中断信号(Ctrl-C);

SIGQUIT:来自键盘的退出信号(Ctrl-\);

SIGFPE: 浮点异常信号(例如 浮点运算溢出);

SIGKILL:该信号结束接收信号的进程;

SIGALRM:进程的定时器到期时,发送该信号;

SIGTERM:kill 命令发出的信号;

SIGCHLD:标识子进程停止或结束的信号;

SIGSTOP:来自键盘(Ctrl-Z)或调试程序的停止执行信号;

…………

三、创建初始化、P、V、销毁信号量操作代码
#include "sem.h"

static int semid = -1;
void sem_init()
{
    semid = semget((key_t)1234,1,IPC_CREAT | IPC_EXCL | 0600);
    if(semid == -1)
    {
        semid = semget((key_t)1234,1,0600);
        if(semid == -1)
        {
            perror("semget error");
            return ;
        }
    }
    else
    {
        union semun a;
        a.val = 1;
        if(semctl(semid,0,SETVAL,a)== -1)
        {
            perror("semctl error");
        }
    }
}
void sem_p()
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op =-1;
    buf.sem_flg =SEM_UNDO;
    if(semop(semid,&buf,1)== -1)
    {
        perror("semop p error");
    }
}
void sem_v()
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 1;
    buf.sem_flg = SEM_UNDO;
    if(semop(semid,&buf,1)== -1)
    {
        perror("semop v error");
    }
}
void sem_destroy()
{
    if(semctl(semid,0,IPC_RMID)== -1)
    {
        perror("semtcl error");
    }
}
4、简单使用信号量来进行同步进程

代码测试目的是为了在三个进程下,通过同步进程来按顺序连续输出abc,最后输出的abc不会颠倒顺序。

a进程

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/sem.h>
#include "sem.h"
int main()
{
    sem_init();
    int i=0;
    for(;i<5;i++)
    {
        sem_p();
        write(1,"A",1);
        int n=rand() %3;
        sleep(n);
        write(1,"A",1);
        sem_v();
        int s=rand() %3;
        sleep(s);
    }
}

b进程

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/sem.h>
#include "sem.h"
int main()
{
    sem_init();
    int i=0;
    for(;i<5;i++)
    {
        sem_p();
        write(1,"B",1);
        int n=rand() %3;
        sleep(n);
        write(1,"B",1);
        sem_v();
        int s=rand() %3;
        sleep(s);
    }
}

c进程

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/sem.h>
#include "sem.h"
int main()
{
    sem_init();
    int i=0;
    for(;i<5;i++)
    {
        sem_p();
        write(1,"C",1);
        int n=rand() %3;
        sleep(n);
        write(1,"C",1);
        sem_v();
        int s=rand() %3;
        sleep(s);
    }
    sleep(10);
    sem_destroy();
}

最后的c进程在睡眠10秒后通过调用sem_destroy()来进行销毁。最后输出结果为连续的5个ABC,达到成功完成实验的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值