2024.1.9 IO线程进程 作业

本文详细介绍了如何在C语言中使用消息队列进行进程间通信,包括线程间的消息发送和接收,并展示了信号处理的不同方式,如默认执行、忽略和捕获。同时,也涉及了共享内存的创建、映射和管理。
摘要由CSDN通过智能技术生成

思维导图

练习题

1> 使用消息队列完成两个进程之间相互通信

程序1

#include <myhead.h>
#define SIZE 1024
//创建消息队列所需的结构体
typedef struct msgbuf
{
    long msgtype;
    char msgtext[SIZE];
} msgBuf;
//线程1函数完成发送消息
void *task1(void *arg)
{
    //创建key
    key_t key = ftok("/", 1);
    if (key == -1)
    {
        perror("create key error");
        return NULL;
    }
    //获取消息队列,如果没有创建消息队列
    int msqid = msgget(key, IPC_CREAT | 0664);
    if (msqid == -1)
    {
        perror("create msgget error");
        return NULL;
    }
    //设置结构体中数据类型
    msgBuf buf = {.msgtype = 1};
    //循环写入消息到消息队列中
    while (1)
    {
        printf("input:");
        //结构体msgtext从终端获取内容
        scanf(" %s", buf.msgtext);
        //将内容写入对应msqid的消息队列中
        msgsnd(msqid, &buf, sizeof(buf.msgtext), 0);
        //输入quit退出循环输入
        if (strcmp(buf.msgtext, "quit") == 0)
            break;
    }
    //删除消息队列
    msgctl(msqid, IPC_RMID, NULL);
}
//线程2函数完成接收消息
void *task2(void *arg)
{
    //创建和发送端一样的key
    key_t key = ftok("/", 2);
    if (key == -1)
    {
        perror("create key error");
        return NULL;
    }
    //创建消息队列
    int msqid = msgget(key, IPC_CREAT | 0664);
    if (msqid == -1)
    {
        perror("create msgid error");
        return NULL;
    }
    msgBuf buf = {.msgtype = 2};
    while (1)
    {
        //获取消息队列中的内容
        msgrcv(msqid, &buf, sizeof(buf.msgtext), 0, 0);
        printf("\noutput:%s\n", buf.msgtext);
        if (strcmp(buf.msgtext, "quit") == 0)
            break;
    }
}
int main(int argc, char const *argv[])
{
    //创建线程名
    pthread_t tid1, tid2;
    if (pthread_create(&tid1, NULL, task1, NULL) == -1)
    {
        printf("create tid1 error");
        return -1;
    }
    if (pthread_create(&tid2, NULL, task2, NULL) == -1)
    {
        printf("create tid1 error");
        return -1;
    }
    //回收线程资源
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    return 0;
}

程序2

#include <myhead.h>
#define SIZE 1024
//创建消息队列所需的结构体
typedef struct msgbuf
{
    long msgtype;
    char msgtext[SIZE];
} msgBuf;
//线程1函数完成发送消息
void *task1(void *arg)
{
    //创建key
    key_t key = ftok("/", 2);
    if (key == -1)
    {
        perror("create key error");
        return NULL;
    }
    //获取消息队列,如果没有创建消息队列
    int msqid = msgget(key, IPC_CREAT | 0664);
    if (msqid == -1)
    {
        perror("create msgget error");
        return NULL;
    }
    //设置结构体中数据类型
    msgBuf buf = {.msgtype = 2};
    //循环写入消息到消息队列中
    while (1)
    {
        printf("input:");
        //结构体msgtext从终端获取内容
        scanf(" %s", buf.msgtext);
        //将内容写入对应msqid的消息队列中
        msgsnd(msqid, &buf, sizeof(buf.msgtext), 0);
        //输入quit退出循环输入
        if (strcmp(buf.msgtext, "quit") == 0)
            break;
    }
    //删除消息队列
    msgctl(msqid, IPC_RMID, NULL);
}
//线程2函数完成接收消息
void *task2(void *arg)
{
    //创建和发送端一样的key
    key_t key = ftok("/", 1);
    if (key == -1)
    {
        perror("create key error");
        return NULL;
    }
    //创建消息队列
    int msqid = msgget(key, IPC_CREAT | 0664);
    if (msqid == -1)
    {
        perror("create msgid error");
        return NULL;
    }
    msgBuf buf = {.msgtype = 1};
    while(1)
    {
        //获取消息队列中的内容
        msgrcv(msqid,&buf,sizeof(buf.msgtext),0,0);
        printf("\noutput:%s\n",buf.msgtext);
        if(strcmp(buf.msgtext,"quit")==0) break;
    }
}
int main(int argc, char const *argv[])
{
    //创建线程名
    pthread_t tid1, tid2;
    if (pthread_create(&tid1, NULL, task1, NULL) == -1)
    {
        printf("create tid1 error");
        return -1;
    }
    if (pthread_create(&tid2, NULL, task2, NULL) == -1)
    {
        printf("create tid1 error");
        return -1;
    }
    //回收线程资源
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    return 0;
}

2> 将信号通信相关代码实现

#include <myhead.h>

int main(int argc, char const *argv[])
{
    //信号处理的3种方式,默认执行(一般为杀死进程)、忽略、捕获
    //绑定从终端获取的信号,默认执行信号内容
    if(signal(SIGINT,SIG_DFL)==SIG_ERR)
    {
        perror("绑定失败");
        return -1;
    }

    int i=0;
    while(1)
    {
        sleep(1);
        i++;
        printf("%d\n",i);
    }
    return 0;
}

#include <myhead.h>

int main(int argc, char const *argv[])
{
    //信号处理的3种方式,默认执行(一般为杀死进程)、忽略、捕获
    //绑定从终端获取的信号,忽略信号内容
    if(signal(SIGINT,SIG_IGN)==SIG_ERR)
    {
        perror("绑定失败");
        return -1;
    }

    int i=0;
    while(1)
    {
        sleep(1);
        i++;
        printf("%d\n",i);
    }
    return 0;
}

#include <myhead.h>
void handler(int signum)
{
    if(signum==SIGINT)
    {
        puts("按下Ctrl+C");
    }
}
int main(int argc, char const *argv[])
{
    //信号处理的3种方式,默认执行(一般为杀死进程)、忽略、捕获
    //绑定从终端获取的信号,捕获信号内容
    if(signal(SIGINT,handler)==SIG_ERR)
    {
        perror("绑定失败");
        return -1;
    }

    int i=0;
    while(1)
    {
        sleep(1);
        i++;
        printf("%d\n",i);
    }
    return 0;
}

#include <myhead.h>

//定义信号处理函数
void handler(int signum)
{
    if (signum == SIGCHLD)
    {
        //以非阻塞的形式回收僵尸进程,直到所有的僵尸进程全部回收结束
        while (waitpid(-1, NULL, WNOHANG) > 0);
    }
}

int main(int argc, const char *argv[])
{

    //捕获子进程发来的SIGCHLD信号
    if (signal(SIGCHLD, handler) == SIG_ERR)
    {
        perror("signal error");
        return -1;
    }

    //创建5个子进程并杀死,成为僵尸进程
    for (int i = 0; i < 4; i++)
    {
        if (fork() == 0)
        {
            exit(EXIT_SUCCESS);
        }
    }
    //父进程阻塞,不会回收子进程
    while (1);

    return 0;
}
#include <myhead.h>
void handler(int signo)
{
    if(signo==SIGUSR1)
    {
        puts("就这样活");
        //杀死父进程
        raise(SIGKILL);
    }
}
int main(int argc, char const *argv[])
{
    //创建子进程
    pid_t pid = fork();
    if (pid > 0)
    {
        //当父进程等待SIGUSER1发来信号,然后捕获信号,执行handler函数
        if(signal(SIGUSR1,handler)==SIG_ERR)
        {
            perror("signal error");
            return -1;
        }
        //阻塞父进程
        while (1)
        {
            puts("活着");
            sleep(1);
        }
    }
    else if (pid == 0)
    {
        puts("好");
        sleep(3);
        puts("怎么活");
        //子进程发送kill信号
        kill(getppid(), SIGUSR1);
        exit(0);
    }
    else
    {
        perror("create pid error");
        return -1;
    }
    return 0;
}

3> 将共享内存相关代码实现

发送端

#include <myhead.h>
#define PAGE_SIZE 4096
int main(int argc, char const *argv[])
{
    //创建key
    key_t key = ftok("/", 1);
    //打印key的地址
    printf("key=%x\n", key);

    //申请物理内存,映射共享内存空间
    int shmid = shmget(key, PAGE_SIZE, IPC_CREAT | 0664);
    if (shmid == -1)
    {
        perror("shmget error");
        return -1;
    }
    //打印内存空间
    printf("shmid=%d\n", shmid);

    //映射共享空间
    char *addr = (char *)shmat(shmid, NULL, 0);
    //打印地址
    printf("addr=%p\n", addr);

    //操作共享内存
    while (1)
    {
        fgets(addr, PAGE_SIZE, stdin); //从终端输入数据
        addr[strlen(addr) - 1] = '\0'; //将换行换成'\0'

        if (strcmp(addr, "quit") == 0)
        {
            break;
        }
    }

    return 0;
}

接收端

#include <myhead.h>
#define PAGE_SIZE 4096

int main(int argc, const char *argv[])
{
    //创建key值
    key_t key = key = ftok("/", 1);
    printf("key = %x\n", key);

    //2、将物理内存创建出共享内存段
    int shmid = shmget(key, PAGE_SIZE, IPC_CREAT | 0664);
    if (shmid == -1)
    {
        perror("shmget error");
        return -1;
    }
    printf("shmid = %d\n", shmid);

    //将共享内存段地址映射到用户空间
    //NULL表示让系统自动选择页的分段
    //0表示当前进程对共享内存具有读写功能
    char *addr = (char *)shmat(shmid, NULL, 0);
    printf("addr = %p\n", addr);

    //操作共享内存
    while (1)
    {
        printf("共享内存中的数据为:%s\n", addr);
        sleep(1);
        if (strcmp(addr, "quit") == 0)
        {
            break;
        }
    }

    //取消映射
    if (shmdt(addr) == -1)
    {
        perror("shmdt error");
        return -1;
    }

    //删除共享内存
    if (shmctl(shmid, IPC_RMID, NULL) == -1)
    {
        perror("shmctl error");
        return -1;
    }

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值