学习_vfork、消息队列和信号处理小小程序

因为自己写的小程序,结构不太严谨

程序实现消息队列的请求和响应步骤,另从子程序发送信号至父程序

实验环境:Linux + vim

进行实验时,应先将b程序生成执行文件b,a程序生成执行文件

命令:gcc -ob b.c

           gcc -oa a.c

 

程序a:

#include <stdio.h>    // 吐槽一下UC的头文件....TM真多
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <signal.h>
#include <unistd.h>

//该结构体是信息包的内容
struct emp
{
    int id;
    char name[20];
    double sal;
};

//消息队列所传递接收的信息包
struct msg
{
    long mtype;    //指定消息包的类型
    struct emp em;  //消息包的内容
};

//信号处理函数:主要是通过捕获信号来销毁创建的队列
void fa(int signo)
{

//接下来两句应该定义成全局变量的,这样就不用在这里写这两句,只是想着自己练习懒得去改
    key_t key = ftok(".",100);     
    int msgid = msgget(key,IPC_CREAT|0666);
    msgctl(msgid,IPC_RMID,0);
    printf("队列销毁!\n");
    exit(0);
}
int main()
{
    signal(40,fa);   //信号捕获函数
    key_t key = ftok(".",100);   //创建消息队列的key,key可以用来创建和获取消息队列,是从用户层与内核交互的钥匙
    int msgid = msgget(key,IPC_CREAT|0666);   //创建消息队列
    if(msgid == -1)
    {
        perror("msgget");
        exit(-1);
    }
    struct emp em1 = {1,"zhangfei",12000.0}; //信息录入
    struct emp em2 = {2,"guanyu",12000.0};
    struct msg m1 = {1,em1};
    struct msg m2 = {2,em2};
    msgsnd(msgid,&m1,sizeof(m1.em),0); //发送信息,将信息传入消息队列中
    msgsnd(msgid,&m2,sizeof(m2.em),0);
    printf("数据发送完成!\n");
    pid_t pid = vfork();   //创建子进程,子进程抢占父进程资源,这时父进程进入阻塞状态
    if(!pid)
    {
        printf("执行读操作\n");
        execl("./b","b",NULL);    //使用exec家族替换子进程,子进程拥有独立的资源,父进程结束阻塞
        perror("execl");               //将名为b的程序替换子进程,并开始运行b
        exit(-1);
    }
    while(1);
}

 

程序b:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <signal.h>
struct emp
{
    int id;
    char name[20];
    double sal;
};
struct msg
{
    long mtype;
    struct emp em;
};
int main()
{
    int ppid = getppid();    //获取父进程的PID,PID是进程的唯一标识。通过它可以向进程进行发送信号等操作
    key_t key = ftok(".",100);
    int msgid = msgget(key,0);  //获取消息队列的id,从而能与父进程对同一块内存进行数据交互
    if(msgid == -1)
    {
        perror("msgget");
        exit(-1);
    }
    struct msg m1;
    while(1)
    {
        int res = msgrcv(msgid,&m1,sizeof(m1.em),-2,IPC_NOWAIT);   //获取消息队列中类型小于等于2的信息包,获取不阻塞
        if(res == -1)
        {
            printf("数据读取完成!\n");
            break;
        }
        printf("%ld,%d%s,%lf\n",m1.mtype,m1.em.id,m1.em.name,m1.em.sal);
    }
    kill(ppid,40);   //向父进程发送信号,使父进程销毁队列
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#ifndef CONFIG_HAVE_COPY_THREAD_TLS /* For compatibility with architectures that call do_fork directly rather than * using the syscall entry points below. */ long do_fork(unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) { struct kernel_clone_args args = { .flags = (clone_flags & ~CSIGNAL), .pidfd = parent_tidptr, .child_tid = child_tidptr, .parent_tid = parent_tidptr, .exit_signal = (clone_flags & CSIGNAL), .stack = stack_start, .stack_size = stack_size, }; if (!legacy_clone_args_valid(&args)) //1.查找 pid 位图,为子进程分配新的 pid return -EINVAL; return _do_fork(&args); } long _do_fork(struct kernel_clone_args *args) { u64 clone_flags = args->flags; struct completion vfork; struct pid *pid; struct task_struct *p; int trace = 0; long nr; //2.关于进程追踪的设置 if (!(clone_flags & CLONE_UNTRACED)) { if (clone_flags & CLONE_VFORK) trace = PTRACE_EVENT_VFORK; else if (args->exit_signal != SIGCHLD) trace = PTRACE_EVENT_CLONE; else trace = PTRACE_EVENT_FORK; if (likely(!ptrace_event_enabled(current, trace))) trace = 0; } //3.复制进程描述符 p = copy_process(NULL, trace, NUMA_NO_NODE, args); add_latent_entropy(); if (IS_ERR(p)) return PTR_ERR(p); trace_sched_process_fork(current, p); pid = get_task_pid(p, PIDTYPE_PID); nr = pid_vnr(pid); if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, args->parent_tid); if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); get_task_struct(p); } //4.将子进程放在运行队列中父进程的前面 wake_up_new_task(p); /* forking complete and child started to run, tell ptracer */ if (unlikely(trace)) ptrace_event_pid(trace, pid); if (clone_flags & CLONE_VFORK) { //5.如果是 vfork() 的话父进程插入等待队列,挂起父进程直到子进程释放自己的内存地址空间 //(直到子进程结束或者执行新的程序) if (!wait_for_vfork_done(p, &vfork)) ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid); } put_pid(pid); return nr; }加上注释
06-11

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值