Linux进程4

本文详细介绍了Linux系统中进程间通信的多种方式,包括使用信号量实现线程循环执行、非阻塞回收子进程资源、捕捉管道破裂信号等。此外,还深入探讨了信号、消息队列、共享内存和信号灯集的概念、API用法及实例,为Linux进程通信提供了全面的知识指导。
摘要由CSDN通过智能技术生成

目录

1.1使用信号量实现两个线程循环执行的过程

1.2使用非阻塞方式回收子进程的资源

1.3捕捉管道破裂信号

2.信号

2.1发信号的函数

2.2kill函数使用实例

2.3raise函数实例

2.4alarm函数实例

2.5alarm函数使用(斗地主倒计时)

3.IPC进程间通信

3.1IPC进程间通信的种类

3.2IPC进程间通信用到的命令

3.3IPC通信键值的获取

4.消息队列

4.1消息队列原理

4.2消息队列的API(msgget|msgsnd|msgrcv|msgctl)

4.3消息队列通信实例1(消息类型相同)

send.c

receive.c

4.4消息队列通信实例2(消息类型不同)

send.c

receive.c

4.5消息队列控制函数msgctl

4.5.1消息队列中属性信息获取及设置

4.5.2消息队列删除

5.共享内存

5.1共享内存的原理

5.2共享内存的API(shmget|shmat|shmdt|shmctl)

5.3共享内存使用实例

write.c

read.c

5.4通过shmctl获取或设置属性

6.信号量(信号灯集)

6.1信号灯集的简介

6.2信号灯集合API(semget|semctl|semop)

6.3信号灯集代码封装

sem.h

sem.c

6.4信号灯集使用实例

write.c

read.c


1.1使用信号量实现两个线程循环执行的过程

#include <head.h>

// 1.定义条件变量
pthread_cond_t cond;
pthread_mutex_t mutex;
int flags = 0;
//生产者线程
void* Task1(void* arg)
{
    while (1) {
        pthread_mutex_lock(&mutex);

        while (flags == 1)
            pthread_cond_wait(&cond, &mutex);

        printf("我生产了一部Mate50保时捷版手机,售价12999\n");
        flags = 1;

        pthread_cond_signal(&cond);

        pthread_mutex_unlock(&mutex);
    }
}

//消费者线程
void* Task2(void* arg)
{
    while (1) {
        pthread_mutex_lock(&mutex);

        while (flags == 0)
            pthread_cond_wait(&cond, &mutex);

        printf("tid=%#lx,花重金购买了一部Mate50保时捷版手机\n", pthread_self());

        flags = 0;
        pthread_cond_signal(&cond);
        sleep(1);
        pthread_mutex_unlock(&mutex);
    }
}
int main(int argc, const char* argv[])
{
    pthread_t tid1, tid2;

    // 2.初始化条件变量,初始化互斥锁
    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);

    if (errno = pthread_create(&tid1, NULL, Task1, NULL))
        PRINT_ERR("pthread create error");

    if (errno = pthread_create(&tid2, NULL, Task2, NULL))
        PRINT_ERR("pthread create error");

    printf("tid2=%#lx\n", tid2);
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    // 4.销毁
    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);

    return 0;
}

1.2使用非阻塞方式回收子进程的资源

#include <head.h>
char buf[128] = {0};
void signal_handle(int signo)
{
    printf("我收到了子进程退出的信号SIGCHLD\n");
    printf("我在使用非阻塞方式回收子进程的资源\n");
    waitpid(-1,NULL,WNOHANG);
    system(buf);
}
int main(int argc, const char* argv[])
{
    pid_t pid;

    snprintf(buf,sizeof(buf),"kill -9 %d",getpid());

    pid = fork();
    if (pid == -1) {
        PRINT_ERR("fork error");
    } else if (pid == 0) {
        printf("child:pid = %d,ppid=%d\n", getpid(), getppid());
        sleep(3);
        exit(EXIT_SUCCESS);

    } else {
        printf("parent:pid = %d,cpid = %d,ppid=%d\n", getpid(), pid, getppid());
        if(SIG_ERR == signal(SIGCHLD,signal_handle))
            PRINT_ERR("register signal error");
        
        while(1);
    }
    return 0;
}

1.3捕捉管道破裂信号

#include <head.h>
void signal_handle(int signo)
{
    printf("我收到了管道破裂的信号\n");
}
int main(int argc, const char* argv[])
{
    int pipefd[2];
    char buf[128] = "hello everyone!!!";
    // 0.注册信号处理函数
    if (SIG_ERR == signal(SIGPIPE, signal_handle))
        PRINT_ERR("register signal error");
    // 1.创建无名管道
    if (pipe(pipefd))
        PRINT_ERR("create pipe error");

    // 2.关闭读端
    close(pipefd[0]);

    // 3.写管道 (管道破裂)
    write(pipefd[1], buf, strlen(buf));

    while (1);
    return 0;
}

2.信号

2.1发信号的函数

int kill(pid_t pid, int sig);
功能:发信号的函数
参数:
    @pid: 进程号
       pid > 0  :将信号发送给这个pid对应的进程
  pid = -1 :给有权限的所有进程发送信号,init除外
        pid = 0  :信号将发送给同组的所有的进程
        pid < -1 :对pid取绝对值,和这个pid同组的所有的进程都能收到信号
            
    @sig: 信号号
返回值:成功返回0,失败返回-1置位错误码
        
int raise(int sig);
功能:给自己发信号
参数:
    @sig:信号号
返回值:成功返回0,非0是失败

unsigned int alarm(unsigned int seconds);
功能:当 seconds倒计时为0的时候,给当前进程发送一个闹钟信号
参数:
    @seconds:秒钟
         >0  倒计时到0的时候会发出闹钟信号
         =0  倒计时到0的时候不会发出闹钟信号
返回值:如果alarm第一调用返回0,如果不是第一次调用返回上一次的剩余秒钟数

2.2kill函数使用实例

#include <head.h>

void signal_handle(int signo)
{
    printf("我收到了子进程退出的信号SIGCHLD\n");
    printf("我在使用非阻塞方式回收子进程的资源\n");
    waitpid(-1,NULL,WNOHANG);
    kill(getpid(),SIGKILL);
}
int main(int argc, const char* argv[])
{
    pid_t pid;

    pid = fork();
    if (pid == -1) {
        PRINT_ERR("fork error");
    } else if (pid == 0) {
        printf("child:pid = %d,ppid=%d\n", getpid(), getppid());
        sleep(3);
        exit(EXIT_SUCCESS);

    } else {
        printf("parent:pid = %d,cpid = %d,ppid=%d\n", getpid(), pid, getppid());
        if(SIG_ERR == signal(SIGCHLD,signal_handle))
            PRINT_ERR("register signal error");
        
        
        while(1);
    }
    return 0;
}
#include <head.h>

//./a.out 22300
int main(int argc,const char * argv[])
{
    kill(atoi(argv[1]),SIGKILL);
    return 0;
}

2.3raise函数实例

#include <head.h>

void signal_handle(int signo)
{
    printf("我收到了子进程退出的信号SIGCHLD\n");
    printf("我在使用非阻塞方式回收子进程的资源\n");
    waitpid(-1,NULL,WNOHANG);
    // kill(getpid(),SIGKILL);
    raise(SIGKILL);
}
int main(int argc, const char* argv[])
{
    pid_t pid;

    pid = fork();
    if (pid == -1) {
        PRINT_ERR("fork error");
    } else if (pid == 0) {
        printf("child:pid = %d,ppid=%d\n", getpid(), getppid());
        sleep(3);
        exit(EXIT_SUCCESS);

    } else {
        printf("parent:pid = %d,cpid = %d,ppid=%d\n", getpid(), pid, getppid());
        if(SIG_ERR == signal(SIGCHLD,signal_handle))
            PRINT_ERR("register signal error");
        
        
        while(1);
    }
    return 0;
}

2.4alarm函数实例

#include <head.h>

void handle(int signo)
{
    if (signo == SIGALRM) {
        printf("我收到了闹钟信号\n");
    }
}
int main(int argc, const char* argv[])
{
    if (SIG_ERR == signal(SIGALRM, handle))
        PRINT_ERR("register siganl error");

    //第一调用alarm的时候返回值是0
    printf("%d\n",alarm(5));
    sleep(2);
    //第二次调用的时候alarm返回值是3
    //但是由于将倒计时又设置为了5,
    //5秒之后会执行信号处理函数
    printf("%d\n",alarm(5));

    while(1);
    return 0;
}

2.5alarm函数使用(斗地主倒计时)

#include <head.h>

void handle(int signo)
{
    printf("系统自动出牌成功了\n");
    alarm(4);
}
int main(int argc, const char* argv[])
{
    char ch;
    if (SIG_ERR == signal(SIGALRM, handle))
        PRINT_ERR("register siganl error");

    alarm(4);

    while(1){
        ch = getchar();
        getchar(); //吃掉垃圾字符'\n'
        printf("手动出牌 = %c\n",ch);
        alarm(4);
    }

    return 0;
}

3.IPC进程间通信

3.1IPC进程间通信的种类

1.消息队列

2.共享内存

3.信号灯集

3.2IPC进程间通信用到的命令

(1)查看(ipcs)

ipcs -q //查看消息队列

ipcs -m //查看共享内存

ipcs -s //查看信号灯集

(2)删除(ipcrm)

ipcrm -q msqid //删除消息队列

ipcrm -m shmid //删除共享内存

ipcrm -s semid //删除信号灯集

3.3IPC通信键值的获取

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值