进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现

进程间通信的实现


文章目录

  • 进程间通信的实现
  • IPC
    • IPC对象
    • ipcs、 ipcrm
    • 共享内存
      • 共享内存(share memory)
      • 共享内存实现
      • 共享内存函数调用流程
      • 共享内存函数
        • shmget
        • shmat
        • shmdt
        • shmctl
      • 举例
    • 消息队列(message queue)
      • 消息队列函数调用流程
      • 消息队列函数
        • msgget
        • msgsnd
        • msgrcv
        • msgctl
      • 举例
    • 信号灯(semaphore)
      • 临界资源
      • semaphore
      • System V信号灯
      • 二值信号灯、计数信号灯
      • PV操作
      • sem函数
        • semget
        • semctl
        • semop
      • 举例
    • 信号量与共享内存
  • 信号
    • 信号通信
    • 信号处理流程
    • 信号类型
    • 信号发送
      • kill()和raise()
    • 设置信号的处理方式
    • 信号设置函数-signal
    • 举例
  • 进程间通讯方式比较


常用的进程间通信方式
• 传统的进程间通信方式
无名管道(pipe)、有名管道(fifo)和信号(signal)
• System V IPC对象
共享内存(share memory)、消息队列(message queue)和信号量(semaphore)
• BSD
套接字(socket)

当前目录下路径指定要加上“.”
ftok (“./app”, ‘i’)才可以
“./”才是当前路径,“/“根目录路径

IPC

IPC对象

IPC(Inter-Process Communication)进程间通信,提供了各种进程间通信的方法
进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第1张图片
进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第2张图片

ipcs、 ipcrm

  1. ipcs命令用于查看系统中的IPC对象
    进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第3张图片

ipcs –m 共享内存
进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第4张图片

ipcs –s 信号量
进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第5张图片

ipcs –q 消息队列
进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第6张图片

  1. ipcrm命令用于删除系统中的IPC对象
    ipcrm –m id
    创建的IPC对象如果不删除的话会一直保留在系统中

共享内存

“./”才是当前路径,“/“根目录路径

共享内存(share memory)

  1. 共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝
  2. 为了在多个进程间交换信息, 内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间
  3. 进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高的效率。
  4. 由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等
    从串口读取的zigbee网络环境数据要发送给web页面或者APP,必须满足:
  • 所有的其他进程都可以定时从”某块内存” 读取数据
  • 有新的数据更新时,可以很方便的将数据写入到” 某块内存”
  • 读取的数据不需要清除原有数据,写入的数据要更新到这块内存

共享内存实现

共享内存的使用包括如下步骤:

  1. 创建/打开共享内存
  2. 映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
  3. 撤销共享内存映射
  4. 删除共享内存对象

共享内存函数调用流程

进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第7张图片

共享内存函数

shmget
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, int size, int shmflg);

key:
IPC_PRIVATE 或 ftok的返回值
size:
共享内存区大小
shmflg:
同open函数的权限位,也可以用8进制表示法
返回值
成功:共享内存段标识符
出错: -1

shmat
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);

shmid:要映射的共享内存区标识符
shmaddr:将共享内存映射到指定地址(若为NULL,则表示由系统自动完成映射)
shmflg :
SHM_RDONLY:共享内存只读
默认0:共享内存可读写

返回值:
成功:映射后的地址
出错: -1

shmdt
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>

shmaddr
:共享内存映射后的地址
返回值
成功: 0
出错:-1

shmctl
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmid:要操作的共享内存标识符
cmd : IPC_STAT (获取对象属性)
IPC_SET (设置对象属性)
IPC_RMID (删除对象)
buf : 指定IPC_STAT/IPC_SET时用以保存/设置属性
返回值
成功: 0
出错:-1

举例

Linux终端放大缩小:
放大:
ctrl+shift+=
缩小:
ctrl±

shm-server.c

/* shm_server.c : the time server using shared memory, a bizarre application  */
#include    <stdio.h>
#include    <sys/shm.h>
#include    <time.h>
#include        <stdlib.h>
#include        <unistd.h>
#include        <string.h>

#define    TIME_MEM_KEY    99    /* like a filename      */
#define    SEG_SIZE    ((size_t)100)    /* size of segment      */

main()
{
    long now;
    int n;
    key_t key_info;
    
    if ((key_info = ftok ("/app", 'i')) < 0)
    {
        perror ("ftok info");
        exit (-1);
    }
    /* create a shared memory segment */
    int seg_id = shmget(key_info, SEG_SIZE, IPC_CREAT | 0777);

    /* attach to it and get a pointer to where it attaches */
    char *mem_ptr = shmat(seg_id, NULL, 0);

    /* run for a minute */
    for (n = 0; n < 60; n++) 
    {
        time(&now);            /* get the time */
        strcpy(mem_ptr, ctime(&now));    /* write to mem */
        sleep(1);            /* wait a sec   */
    }
    shmctl(seg_id, IPC_RMID, NULL);
}

进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第8张图片

shm-client.c

/* shm_client.c : the time client using shared memory, a bizarre application  */
#include        <stdlib.h>
#include        <unistd.h>
#include    <stdio.h>
#include    <sys/shm.h>
#include    <time.h>

#define    TIME_MEM_KEY    99
#define    SEG_SIZE    ((size_t)100)


main()
{
    key_t key_info;
    
    if ((key_info = ftok ("/app", 'i')) < 0)
    {
        perror ("ftok info");
        exit (-1);
    }
    int seg_id = shmget(key_info, SEG_SIZE, 0777);
    
    char *mem_ptr = shmat(seg_id, NULL, 0);
    
    printf("The time, direct from memory: ..%s", mem_ptr);
    shmdt(mem_ptr);
}

进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第9张图片

share.c
#include <sys/ipc.h>
 #include <sys/shm.h>
#include <stdio.h>
#include <sys/stat.h>
 int shmctl(int shmid, int cmd, struct shmid_ds *buf);


int main()
{
    int  segment_id,segment_size;
    char *shared_memory;
    struct shmid_ds shmbuffer;
    const int shared_segment_size = 0x6400;
/*分配*/
    segment_id = shmget (IPC_PRIVATE, shared_segment_size, 
                      IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR ); 


    shared_memory = (char*) shmat (segment_id, 0, 0); 
    printf ("shared memory attached at address %p\n", shared_memory); 


    shmctl (segment_id, IPC_STAT, &shmbuffer); 

    segment_size = shmbuffer.shm_segsz; 
    printf ("segment size: %d\n", segment_size); 
    sprintf (shared_memory, "Hello, world."); 

    shmdt (shared_memory); 

/*绑定到共享内存块*/
    shared_memory = (char*) shmat (segment_id, (void*) 0x500000, 0); 
    printf ("shared memory reattached at address %p\n",shared_memory); 

    printf ("%s\n", shared_memory);
    
    /*tuo li*/
    shmdt (shared_memory); 
    /*释放内存*/
    shmctl (segment_id, IPC_RMID, 0); 
    return;

}

消息队列(message queue)

  • 消息队列是IPC对象的一种
  • 消息队列由消息队列ID来唯一标识
  • 消息队列就是一个消息的列表。 用户可以在消息队列中添加消息、 读取消息等。
  • 消息队列可以按照类型来发送/接收消息
    进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第10张图片

消息队列函数调用流程

进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第11张图片

消息队列函数

msgget
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int flag);

key:和消息队列关联的key值

flag:消息队列的访问权限

返回值:
成功:消息队列ID
出错: -1

msgsnd
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t size,int flag);

msqid:消息队列的ID
msgp:指向消息的指针。常用消息结构msgbuf如下:

struct msgbuf
{
long mtype; //消息类型
char mtext[N]//消息正文
}

size:发送的消息正文的字节数

flag:
IPC_NOWAIT 消息没有发送完成函数也会立即返回。
0:直到发送完成函数才返回
返回值:
成功:0
出错: -1

msgrcv
 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

 int msgrcv(int msgid,  void* msgp,  size_t  size,  long msgtype,  int  flag);

函数参数
msqid:消息队列的ID
msgp:接收消息的缓冲区
size:要接收的消息的字节数
msgtype:
0:接收消息队列中第一个消息。
大于0:接收消息队列中第一个类型为msgtyp的消息.
小于0:接收消息队列中类型值不小于msgtyp的绝对值且类型值又最小的消息。
flag:
0:若无消息函数会一直阻塞
IPC_NOWAIT:若没有消息,进程会立即返回ENOMSG。
函数返回值
成功:接收到的消息的长度
出错:-1

msgctl
 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );

函数参数
msqid:消息队列的队列ID
cmd:
IPC_STAT:读取消息队列的属性,并将其保存在buf指向的缓冲区中。
IPC_SET:设置消息队列的属性。这个值取自buf
IPC_RMID:从系统中删除消息队列。
buf:消息队列缓冲区函数
返回值 成功:0
出错:-1

举例

server

#include<stdio.h>
#include<fcntl.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/stat.h>

#define QUEUE_MSG_LEN    256
#define PROJ_ID        'g'
#define PATH_NAME    "/app"
#define SERVER_MSG    1
#define CLIENT_MSG    2
/*message data structure */
struct msg 
{
    long type;
    long msgtype;
    unsigned char text[QUEUE_MSG_LEN];

};

int main(void)
{
    /*message data structure */
    struct msg msg_buf;


    int qid;
    int msglen;
    int i=0;
    /*get message queue */
    key_t msgkey;
    if ((msgkey = ftok(PATH_NAME, PROJ_ID)) == -1) 
    {
        perror("ftok error!\n");
        exit(1);
    }
    if ((qid = msgget(msgkey, IPC_CREAT | 0666)) == -1) 
    {
        perror("msgget error!\n");
        exit(1);
    }

    while (1) 
    {
        printf("server send: ");
        /*get string from terminal & fill up message data structure */
        fgets(msg_buf.text, QUEUE_MSG_LEN, stdin);
        if (strncmp("exit", msg_buf.text, 4) == 0) 
        {
            msgctl(qid, IPC_RMID, NULL);
            break;
        }
        msg_buf.text[strlen(msg_buf.text) - 1] = '\0';
        msg_buf.type = SERVER_MSG;
        msg_buf.msgtype = i++;

        /*send message to message queue with SERVER_MSG type */
        if (msgsnd(qid, &msg_buf, sizeof(struct msg) - sizeof(long), 0) == -1) 
        {
            perror("Server msgsnd error!\n");
            exit(1);
        }
#if 1
        /*receive message from message queue with CLIENT_MSG type */
        if (msgrcv(qid, &msg_buf, sizeof(struct msg) - sizeof(long), CLIENT_MSG, 0) == -1) 
        {
            perror("Server msgrcv error!\n");
            exit(1);
        }
        printf("server rcv: %d: %s\n",msg_buf.msgtype,msg_buf.text);
#endif        
    }

    exit(0);
}

client

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>

#define QUEUE_MSG_LEN    256
#define PROJ_ID        'g'
#define PATH_NAME    "/app"
#define SERVER_MSG    1
#define CLIENT_MSG    2
/*message data structure */
struct msg 
{
    long type;
    long msgtype;
    unsigned char text[QUEUE_MSG_LEN];

};

int main(void)
{
    int qid;
    int msglen;
    int i=0;
    struct msg msg_buf;

    /* get a message queue */
    key_t msgkey;
    if ((msgkey = ftok(PATH_NAME, PROJ_ID)) == -1) //得到ID,
    {
        perror("ftok error!\n");
        exit(1);
    }
    if ((qid = msgget(msgkey, IPC_CREAT | 0666)) == -1) 
    {
        perror("msgget error!\n");
        exit(1);
    }

    while (1) 
    {
        /*receive message from message queue with SERVER_MSG type */
        if (msgrcv(qid, &msg_buf, sizeof(struct msg) - sizeof(long), SERVER_MSG, 0) == -1) 
        {
            perror("Server msgrcv error!\n");
            exit(1);
        }
        printf("server rcv : %ld: %s\n",msg_buf.msgtype,msg_buf.text);    
#if 1
        printf("client send: ");

        /*get string from terminal & fill up message data structure */
        fgets(msg_buf.text, QUEUE_MSG_LEN, stdin);
        if (strncmp("exit", msg_buf.text, 4) == 0) 
        {
            break;
        }
        msg_buf.text[strlen(msg_buf.text) - 1] = '\0';
        msg_buf.type = CLIENT_MSG;
        msg_buf.msgtype = i++;

        /*send message to message queue with CLIENT_MSG type */
        if (msgsnd(qid, &msg_buf, strlen(msg_buf.text) + 1+4, 0) == -1) 
        {
            perror("client msgsnd error!\n");
            exit(1);
        }
        #endif
    }
    exit(0);
}

进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第12张图片

信号灯(semaphore)

临界资源

  1. 一次只允许一个进程使用的资源称为临界资源;
    临界资源并不全是硬件或是软件,而是两者都能作为临界资源。
    比如硬件的有:打印机、磁带机等;
    软件有: 消息缓冲队列、变量、数组、缓冲区等;
  2. 临界区(critical region)

访问共享变量的程序代码段称为临界区,也称为临界段(criticalsection) ;

  1. 进程互斥

两个或两个以上的进程不能同时进入关于同一组共享变量的临界区,否可可能会发生与时间有关的错误,这种现象称为进程互斥;

semaphore

信号灯(semaphore),也叫信号量。它是不同进程间或一个给定进程内部不同线程间同步的机制。信号灯种类:

  • posix有名信号灯(可用于线程、进程同步)
  • posix基于内存的信号灯(无名信号灯)
  • System V信号灯(IPC对象)

System V信号灯

System V的信号灯是一个或者多个信号灯的一个集合。其中的每一个都是单独的计数信号灯。
而Posix信号灯指的是单个计数信号灯
System V 信号灯由内核维护

二值信号灯、计数信号灯

二值信号灯:
• 值为0或1。与互斥锁类似,资源可用时值为1,不可用时值为0
计数信号灯:
• 值在0到n之间。用来统计资源,其值代表可用资源数

PV操作

通常把信号量操作抽象成PV操作
P
等待操作是等待信号灯的值变为大于0,然后将其减1;
V
释放操作则相反,用来唤醒等待资源的进程或者线程

sem函数

semget
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg);

函数参数
key:和信号灯集关联的key值
nsems: 信号灯集中包含的信号灯数目
semflg:信号灯集的访问权限,通常为IPC_CREAT | 0666
函数返回值
成功:信号灯集ID
出错:-1

semctl
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semctl ( int semid, int semnum,  int cmd…/union semun arg/);

函数参数
semid:信号灯集ID
semnum: 要修改的信号灯编号
cmd:
GETVAL:获取信号灯的值
SETVAL:设置信号灯的值
IPC_RMID:从系统中删除信号灯集合

union semun {
short val;                       /SETVAL用的值/
struct semid_ds* buf;   /IPC_STAT、IPC_SET用的semid_ds结构/ unsigned short* array;
/SETALL、GETALL用的数组值/
struct seminfo *buf;     /为控制IPC_INFO提供的缓存/
} arg;

函数返回值
成功:0
出错:-1错误原因存于errno中

semop
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semop ( int semid, struct sembuf  *opsptr,  size_t  nops);

函数参数
semid:信号灯集ID

struct sembuf {
short  sem_num;  //  要操作的信号灯的编号
short  sem_op;   //    0 :  等待,直到信号灯的值变成0
//   1  :  释放资源,V操作
//   -1 :  分配资源,P操作
short  sem_flg; // 0,  IPC_NOWAIT,  SEM_UNDO
};

nops: 要操作的信号灯的个数
函数返回值
成功:0
出错:-1

为SEM_UNDO时,它将使操作系统跟踪当前进程对这个信号量的修改情况,如果这个进程在没有释放该信号量的情况下终止,操作系统将自动释放该进程持有的信号量。

举例

sem.h

#ifndef __SEM_H__
#define __SEM_H__

#if 0
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
                                (Linux-specific) */
};
#endif
int init_sem(int semid, int num, int val)
{
    union semun myun;
    myun.val = val;
    if(semctl(semid, num, SETVAL, myun) < 0)
    {
        perror("semctl");
        exit(1);
    }
    return 0;
}

int sem_p(int semid, int num)
{
    struct sembuf mybuf;
    mybuf.sem_num = num;
    mybuf.sem_op = -1;
    mybuf.sem_flg = SEM_UNDO;
    if(semop(semid, &mybuf, 1) < 0)
    {
        perror("semop");
        exit(1);
    }

    return 0;
}

int sem_v(int semid, int num)
{
    struct sembuf mybuf;
    mybuf.sem_num = num;
    mybuf.sem_op = 1;
    mybuf.sem_flg = SEM_UNDO;
    if(semop(semid, &mybuf, 1) < 0)
    {
        perror("semop");
        exit(1);
    }

    return 0;
}

#endif

client

#include <sys/types.h>
#include <linux/sem.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "sem.h"

int main(void)
{
    key_t key;   //sem key
    int semid, semval;

    //get semaphore
    if((key = ftok("/app",'i')) <0)
    {
        perror("ftok");
        exit(1);
    }
    printf("key = %x\n",key);

    if((semid  = semget(key, 1, 0666)) < 0)
    {
        perror("semget");
        exit(1);
    }

    //get semaphore value every 1 seconds  
    while (1) 
    {
        if ((semval = semctl(semid, 0, GETVAL, 0)) == -1) 
        {
            perror("semctl error!\n");
            exit(1);
        }

        if (semval > 0) 
        {
            printf("Still %d resources can be used\n", semval);
        }else 
        {
            printf("No more resources can be used!\n");
            //break;
        }
        sleep(1);
    }
    exit(0);
}

server

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <linux/sem.h>
#include <stdio.h>
#include <errno.h>
#include "sem.h"
#define MAX_RESOURCE    10
int main(void)
{
key_t key_info;
int semid;
//get semaphore 
if ((key_info = ftok ("/app", 'i')) < 0)
{
    perror ("ftok info");
    exit (-1);
}


printf("key is %d\n", key_info);

if ((semid = semget (key_info, 1, IPC_CREAT | IPC_EXCL |0666)) < 0)
{
    if (errno == EEXIST)
    {
        semid = semget (key_info, 1, 0666);
    }
    else
    {
        perror ("semget");
        exit (-1);
    }
}
else
{
    init_sem (semid, 0, 1);
}

//substract 1 every 3 seconds until semaphore value is -1
while (1) 
{
    //p
    printf("p\n");
    sem_p (semid, 0);
    //进入临界区
    sleep(4);
    //V
    printf("v\n");
    sem_v (semid, 0);
    sleep(3);
}
exit(0);

}

进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第13张图片

信号量与共享内存

进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第14张图片

信号

当我们按下ctrl+c终止主控程序时,希望能够实现如下操作:
1.进程退出
2.释放所有申请的资源
互斥锁、条件变量、消息队列、共享内存、信号量、线程、设备文件描述符(摄像头、串口)

信号通信

• 信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式
• 信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。
• 如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它;
• 如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程
信号的生存周期

用户进程对信号的响应方式:
• 忽略信号:• 对信号不做任何处理,但是有两个信号不能忽略:即SIGKILL及SIGSTOP。
• 捕捉信号:• 定义信号处理函数,当信号发生时,执行相应的处理函数。
• 执行缺省操作:• Linux对每种信号都规定了默认操作

信号处理流程

进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第15张图片

信号类型

  • SIGHUP

含义
该信号在用户终端连接(正常或非正常)结束时发出,
通常是在终端的控制进程结束时,通知同一会话内的各个作业与控制终端不再关联。
默认操作
终止

  • SIGINT

该信号在用户键入INTR字符(通常是Ctrl-C)时发出, 终端驱动程序发送此信号并送到前台进程中的每一个进程。
终止

  • SIGQUIT
    该信号和SIGINT类似,但由QUIT字符(通常是 Ctrl-)来控制。
    终止

  • SIGILL
    该信号在一个进程企图执行一条非法指令时(可执行文件本身出现错误,或者试图执行数据段、堆栈溢出时)发出。
    终止

  • SIGFPE
    该信号在发生致命的算术运算错误时发出。这里不仅包括浮点运算错误,还包括溢出及除数为0等其它所有的算术的错误。
    终止

  • SIGKILL
    该信号用来立即结束程序的运行,并且不能被阻塞、处理和忽略。
    终止

  • SIGALRM
    该信号当一个定时器到时的时候发出。
    终止

  • SIGSTOP
    该信号用于暂停一个进程,且不能被阻塞、处理或忽略。
    暂停进程

  • SIGTSTP
    该信号用于暂停交互进程,用户可键入SUSP字符(通常是Ctrl-Z)发出这个信号。
    暂停进程

  • SIGCHLD
    子进程改变状态时,父进程会收到这个信号
    忽略

  • SIGABORT
    该信号用于结束进程
    终止

信号发送

kill()和raise()

• kill函数同读者熟知的kill系统命令一样,可以发送信号给进程或进程组(实际上, kill系统命令只是kill函数的一个用户接口)。
• kill – l 命令查看系统支持的信号列表
• Raise 函数允许进程向自己发送信号

NAME
raise - send a signal to the caller
SYNOPSIS
#include <signal.h>
   int raise(int sig);
DESCRIPTION
       The raise() function sends a signal to the calling process or thread.  In a single-threaded program it is equivalent to

           kill(getpid(), sig);

       In a multithreaded program it is equivalent to

           pthread_kill(pthread_self(), sig);

       If the signal causes a handler to be called, raise() will return only after the signal handler has returned.

设置信号的处理方式

• 一个进程可以设定对信号的相应方式
• 信号处理的主要方法有两种
使用简单的signal()函数
使用信号集函数族sigaction
• signal()
使用signal函数处理时,需指定要处理的信号和处理函数
使用简单、易于理解

信号设置函数-signal

#include <signal.h>
void (*signal(int signum, void (*handler)(int)))(int); 
//void (*handler)(int)函数指针

signum:指定信号
handler:
SIG_IGN:忽略该信号。
SIG_DFL:采用系统默认方式处理信号。
自定义的信号处理函数指针
函数返回值
成功:设置之前的信号处理方式
出错:-1

举例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>

void sig_handler(int signo);

int main(int argc, char *argv[])
{
    int time_left;
    
    #if 1
    if (signal(SIGINT, sig_handler) == SIG_ERR) {
        perror("signal error");
        return -1;
    }
    signal(SIGQUIT, sig_handler);    
    #endif
    printf("begin sleep ...\n");
    time_left = sleep(10);
    printf("end sleep ... time_left=%d\n", time_left);
    while(1);
    return 0;
}

void sig_handler(int signo)
{
    if (signo == SIGINT)
        printf("I received a SIGINT!\n");
  signal(SIGINT, SIG_DFL)if (signo == SIGQUIT)
        printf("I received a SIGQUIT!\n");    
}

进程间通信IPC(共享内存,消息队列,信号灯)和信号的具体实现_第16张图片

进程间通讯方式比较

• signa(信号)l: 唯一的异步通信方式
• msg(消息队列):常用于cs模式中, 按消息类型访问,可有优先级
• shm(共享内存):效率最高(直接访问内存) ,需要同步、互斥机制
• sem(信号量):配合共享内存使用,用以实现同步和互斥
• pipe(管道): 具有亲缘关系的进程间,单工,数据在内存中
• fifo: 可用于任意进程间,双工,有文件名,数据在内存,mkfifo file
• Socket:不同主机之间进程通信

你可能感兴趣的:(应用开发,项目,#,物联网项目,c语言,驱动开发,linux,arm,进程间通信)