进程间通信(二)

信号的定义

1.signal 设置信号处理方式

#include <signal.h>    //所需头文件
 
typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);
//int signum(指定信号编号(kill -l))
//ighandler_t handler(SIG_IGN:忽略参数signum指定的信号;自定义信号函数处理指针)

2.验证signal函数

#include <signal.h>
#include <stdio.h>

void handler (int signum)
{
        switch(signum){
                case 2:
                        printf("this is SIGINT\n");
                        break;
                case 9:
                        printf("this is SIGKILL\n");
                        break;
                case 10:
                        printf("this is SIGUSR!\n");
                        break;
        }
        printf("get signum :%d\n",signum);
        printf("jiubu guandiao\n");
}
int main()
{
        signal(SIGINT,handler);  //自定义信号函数处理指针
//      signal(SIGINT,SIG_IGN);
        signal(SIGKILL,handler);
//      signal(SIGKILL,SIG_IGN);   //SIG_IGN:忽略参数signum指定的信号
        signal(SIGUSR1,handler);
//      signal(SIGUSR1,SIG_IGN);
        while(1);
        return 0;
}

3.kill信号处理发送函数

#include <sys/types.h>
#include <signal.h>

int kill(pid_t pid, int sig);
//pid_t pid(进程的pid号,可用ps aux|grep a.out(进程名))
//int sig(代表的信号编号)

4.sprintf把格式化的数据写入某个字符串

#include <stdio.h>

int sprintf(char *str, const char *format, ...);//制作一个指令,放在char *str,然后再使用system()调用。
//char *str(存放数据的字符串)
//const char *format(格式化字符串,即在程序中想要的格式)

5.验证kill函数和sprintf函数

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>


int main(int arge,char **argv)
{
        int signum; 
        int pid;
        char buf[128] = {0};
        signum = atoi(argv[1]);  //将第一个输入 转换成整型数
        pid = atoi(argv[2]);      //将第二个输入 转换成整型数
        printf("signum:%d  pid:%d\n",signum,pid);

//      kill(pid,signum); 
        sprintf(buf,"kill %d %d",signum,pid);
        system(buf);
    
        return 0;
}   

6.sigaction 查询和设置信号处理方式

#include <signal.h>

 int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
//int signum(可以指定SIGKILL和SIGSTOP以外的所有信号)
//const struct sigaction *act(设置指针指向结构体)
/* 
struct sigaction {
   void       (*sa_handler)(int); //信号处理程序,不接受额外数据,SIG_IGN 为忽略,SIG_DFL 为默认动作
   void       (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序,能够接受额外数据和sigqueue配合使用(要配)
   sigset_t   sa_mask;//阻塞关键字的信号集,可以再调用捕捉函数之前,把信号添加到信号阻塞字,信号捕捉函数返回之前恢复为原先的值(默认阻塞,可不配置)。
   int        sa_flags;//影响信号的行为SA_SIGINFO表示能够接受数据(接收一定要加的)
 };
*/
//struct sigaction *oldact(NULL)

7.验证sigaction函数(接收)

#include <signal.h>
#include <stdio.h>
//void     (*sa_sigaction)(int, siginfo_t *, void *);

void handler(int signum,siginfo_t *info,void *context)
{
        printf("get signum:%d\n",signum);//获取信号排列数

        if(context != NULL){  //判断context中是否有内容,再进行结构体指针的调用
                printf("get data:%d\n",info->si_int);
                printf("get data:%d\n",info->si_value.sival_int);
                printf("from pro pid:%d\n",info->si_pid);
        }
}
int main()
{
        struct sigaction sig;    //定义sig类结构体

        printf("pid=%d\n",getpid());

        sig.sa_sigaction = handler;  //定义sa_sigaction=handler函数
        sig.sa_flags = SA_SIGINFO;   //设置信号处理函数是带有三个参数的sa_sigaction
//int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
        sigaction(SIGUSR1,&sig,NULL);
        while(1);
        return 0;
}

8.sigqueue信号的发送携带数据

#include <signal.h>

int sigqueue(pid_t pid, int sig, const union sigval value);
//pid_t pid(进程的pid号,可用ps aux|grep a.out(进程名))
//int sig(代表的信号编号)
//const union sigval value(携带的数据)
union sigval {
               int   sival_int;//数据
               void *sival_ptr;
           };

9.验证sigqueue函数(发送)

#include <stdio.h>
#include <signal.h>

//       int sigqueue(pid_t pid, int sig, const union sigval value);


int main(int arge,char **argv)
{
        int pid;
        int signum;

        signum = atoi(argv[1]);
        pid = atoi(argv[2]);

        union sigval value;
        value.sival_int = "lixiang";

        sigqueue(pid,signum,value);
        printf("pid:%d\n",getpid());
        return 0;
}

10.信号量

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

int semget(key_t key, int num_sems, int sem_flags);// 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
//key_t key = key_t ftok(const char *pathname, int proj_id);
//int num_sems(创建信号量集中信号量的个数)
//int sem_flags(如果内核中不存在键值与key相等的信号量集,则新建一个信号量集(IPC_CREAT|0666);如果存在这样的信号量集,返回此信号量集的标识符)

int semop(int semid, struct sembuf semoparray[], size_t numops);  // 对信号量组进行操作(P、V),改变信号量的值:成功返回0,失败返回-1
//int semid(semget返回信号量集ID)
//struct sembuf semoparray[](指向进行操作的信号量集结构体数组的首地址)
//size_t numops(进行操作信号量的个数)

int semctl(int semid, int sem_num, int cmd, union semun arg);// 控制信号量的相关信息
//int semid(semget返回信号量集ID)
//int sem_num(表示某一个信号量,0为第一个	)
//int cmd(IPC_RMID)从内核中删除信号量集合
//int cmd(SETVAL)用联合体中val成员的值设置信号量集合中单个信号量的值
//union semun arg(结构体)

11.实现信号量

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
//       int semget(key_t key, int nsems, int semflg);
//int semctl(int semid, int semnum, int cmd, ...);
//int semop(int semid, struct sembuf *sops, unsigned nsops);

void pGetKey(int id)
{
        struct sembuf set;
        set.sem_num = 0;
        set.sem_op = -1;      //将信号量对象中序号为0的信号量减1
        set.sem_flg = SEM_UNDO;
        semop(id,&set,1);
        printf("get key\n");
}

void vBackKey(int id)
{
        struct sembuf set;
        set.sem_num = 0;
        set.sem_op = 1;      //将信号量对象中序号为0的信号量加1
        set.sem_flg = SEM_UNDO;//可以避免因为进程异常退出而造成的死锁
        semop(id,&set,1);
        printf("back key\n");
}
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) */
};

int main(int arge , char **argv)
{
        int semid;
        key_t key;
        key = ftok(".",2);
        semid = semget(key,1,IPC_CREAT|0666);   //创建一个信号量组,返回信号量集ID;1表示只有一个信号量

        union semun initsem;
        initsem.val = 0;//锁的个数   //SETVAL用的值
        semctl(semid,0,SETVAL,initsem);//创建一个信号量集对象

        int pid = fork();           //创建一个进程
        if(pid > 0){
                pGetKey(semid);       //2.P操作,拿走一个钥匙(等待钥匙)
                printf("this is father\n");
                vBackKey(semid);      //3.V操作,放回一个钥匙
                semctl(semid,0,IPC_RMID);  //4.从内核中删除信号量集合
        }else if(pid == 0){
                printf("this is chile\n");
                vBackKey(semid);      //1.V操作,放入一个钥匙
        }else{
                printf("chuanjian shibai\n");
        }

        return 0;
}
     


12.配合共享内存使用信号量

1.读数据

#include <stdio.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/sem.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
                                           (Linux-specific) */
};

void PGetKey(int semid)
{
        struct sembuf sops;
        sops.sem_num = 0;        /* Operate on semaphore 0 */
        sops.sem_op = -1;         /* Wait for value to equal 0 */
        sops.sem_flg = SEM_UNDO;
        semop(semid, &sops, 1);
        printf("get key\n");
}


void VReturnKey(int semid)
{
        struct sembuf sops;
        sops.sem_num = 0;        /* Operate on semaphore 0 */
        sops.sem_op = 1;         /* Wait for value to equal 0 */
        sops.sem_flg = SEM_UNDO;
        semop(semid, &sops, 1);
        printf("return key\n");
}

int main()
{
        key_t key;
        int shmid;
        int semid;
        char *pShmAdd;

        key = ftok(".",1);
        //int shmget(key_t key, size_t size, int msgflg);
        shmid = shmget(key,1024*4,IPC_CREAT|0666);

        //void *shmat(int shm_id, const void *addr, int flag);
        pShmAdd = shmat(shmid,0,0);

        semid = semget(key, 1, IPC_CREAT|0666);
        if(semid == -1){
                printf("creation file\n");
        }
        union semun arg;
        arg.val =0;
        semctl(semid,0, SETVAL,arg);

        PGetKey(semid);

        printf("read:%s\n",pShmAdd);
        VReturnKey(semid);
        shmdt(pShmAdd);
        semctl(semid,0, IPC_RMID);
        shmctl(shmid,IPC_RMID,0);
        return 0;
}

2.写数据

#include <stdio.h>
#include <sys/shm.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/sem.h>

void PGetKey(int semid)
{
        struct sembuf sops;
        sops.sem_num = 0;        /* Operate on semaphore 0 */
        sops.sem_op = -1;         /* Wait for value to equal 0 */
        sops.sem_flg = SEM_UNDO;
        semop(semid, &sops, 1);
        printf("get key\n");
}


void VReturnKey(int semid)
{
        struct sembuf sops;
        sops.sem_num = 0;        /* Operate on semaphore 0 */
        sops.sem_op = 1;         /* Wait for value to equal 0 */
        sops.sem_flg = SEM_UNDO;
        semop(semid, &sops, 1);
        printf("return key\n");

}


int main()
{
        key_t key;
        int shmid;
        int semid;
        char *pShmAdd;
		        key = ftok(".",1);
        //int shmget(key_t key, size_t size, int msgflg);
        shmid = shmget(key,1024*4,0);

        //void *shmat(int shm_id, const void *addr, int flag);
        pShmAdd = shmat(shmid,0,0);
        strcpy(pShmAdd,"LiXiang 123456\n");

        semid = semget(key, 0, 0);
        if(semid == -1){
                printf("creation file\n");
        }
        VReturnKey(semid);

        shmdt(pShmAdd);
        return 0;
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值