嵌入式Linux进程间通信 IPC

嵌入式Linux多任务:线程、进程
硬件条件:单个CPU单个核
单任务:一个任务执行完毕之后,下个任务才能执行;
多任务:任务的执行可以被中断,终端之后可以执行其他任务;(并发/并行)
单核CPU:并发
多核CPU:并发、并行

进程实现多任务;特点:给每个进程分配独立的地址空间,4G的大小(1G内核,3G用户空间:栈、堆、数据段、代码段);互不干扰
进程创建方式:fork >exec函数族 > system > vfork
进程的退出:exit()库函数/清理缓冲 _exit()系统待用API/不清理缓冲;
进程等待:wait();解决僵尸进程

进程间通信 IPC
广义进程间通信:A进程-------文件--------B进程
A进程-------数据库-----B进程
狭义进程间通信 :管道、信号、消息队列、共享内存、信号量、套接字
①管道: 无名管道(用于父子进程)

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

int main()
{
    pid_t pid;


    int fd[2];

    if (pipe(fd) < 0)
    {
        perror("pipe fork error!");
        exit(1);
    }

    pid = fork();

    if (pid == -1)
    {
        perror("fork error!");
        exit(1);
    }

    if (pid == 0)
    {
        //无名管道
        close(fd[0]);
        char buf[100];
        while (1)
        {
            scanf("%s", buf);
            write(fd[1], buf, strlen(buf));
        }

    }
    else if (pid > 0)
    {
        char buf[100] = {0};
        while (1)
        {
            int len = read(fd[0], buf, sizeof(buf));
            buf[len] = '\0';
            printf("recv = %s\n", buf);
        }

    }

    return 0;
    }

有名管道
有名管道的使用步骤 :进程调用mkfifo创建有名管道(int mkfifo(const char *pathname, mode_t mode);)------>open打开有名管道--------->read/write读写管道进行通信

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

int main()
{
    pid_t pid;

    if (mkfifo("/tmp/p1", 0644) < 0)
    {
        perror("mkfifo error!");
        exit(1);
    }

    pid = fork();

    if (pid == -1)
    {
        perror("fork error!");
        exit(1);
    }

    if (pid == 0)
    {

        int fd = open("/tmp/p1", O_WRONLY);
        if (fd == -1)
        {
            perror("open file error!");
            exit(1);
        }

        char buf[100] = {0};

        while (1)
        {
            scanf("%s", buf);
            write(fd, buf, strlen(buf));
        }
    }
    else if (pid > 0)
    {

        int fd = open("/tmp/p1", O_RDONLY);
        if (fd == -1)
        {
            perror("open file error!");
            exit(1);
        }

        char buf[100] = {0};
        while (1)
        {
            int len = read(fd, buf, sizeof(buf));
            buf[len] = '\0';
            printf("recv = %s\n", buf);
        }
    }

    return 0;
}

②消息队列(消息队列的本质就是由内核创建的用于存放消息的链表,由于是存放消息的,所以我们就把这个链表称为消息队列。)

消息队列的使用步骤:使用msgget函数创建新的消息队列、或者获取已存在的某个消息队列,并返回唯一标识消息队列的,标识符(msqID),后续收发消息就是使用这个标识符来实现的。----------->收发消息----------->使用msgctl函数,利用消息队列标识符删除消息队列.

消息队列的特点: 传送有格式的消息流 、 多进程网状交叉通信时,消息队列是上上之选 、 能实现大规模数据的通信

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

struct msgbuf
{
    /* data */
    long id;
    char buf[100];
};

int main()
{
    pid_t pid;

    key_t key;
    key = ftok("/tmp/1", 'a');

    //msgid消息队列描述符 == 文件描述符
    int msgid = msgget(key, IPC_CREAT | 0644);
    //int msgid = msgget(IPC_PRIVATE, IPC_CREAT | 0644);

    if (msgid < 0)
    {
        perror("msg get error!");
        exit(1);
    }

    pid = fork();

    if (pid < 0)
    {
        perror("fork error!");
        exit(1);
    }

    if (pid == 0)
    {
        //msgid
        struct msgbuf msg;
        msg.id = 1;
        strcpy(msg.buf, "hello world");
        msgsnd(msgid, &msg, sizeof(struct msgbuf), 0);

        msg.id = 2;
        strcpy(msg.buf, "hello world2");
        msgsnd(msgid, &msg, sizeof(struct msgbuf), 0);
        
        msg.id = 3;
        strcpy(msg.buf, "hello world3");
        msgsnd(msgid, &msg, sizeof(struct msgbuf), 0);
    }
    else if (pid > 0)
    {
        //msgid

        struct msgbuf msg;

        msgrcv(msgid, &msg, sizeof(struct msgbuf), 2, 0);

        printf("recv:%s\n", msg.buf);

        wait(NULL);

        msgctl(msgid,IPC_RMID,NULL);
    }

    return 0;
}

③共享内存(让同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新)

共享内存的使用步骤:进程调用shmget函数创建新的或获取已有共享内存----->进程调用shmat函数,将物理内存映射到自己的进程空间-------->shmdt函数,取消映射-------->调用shmctl函数释放开辟的那片物理内存空间

共享内存的特点 : 减少进入内核空间的次数 、 直接使用地址来读写缓存时,效率会更高,适用于大数据量的通信

#include<stdio.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<stdlib.h>
#include<unistd.h>

int  main()
{
    pid_t pid;
    key_t key;
    key = ftok("/tmp/p2",'b');

    int shmid = shmget(key,1024,0664 | IPC_CREAT);
    if(shmid<0){
        perror("shm get error");
        exit(1);
    }
    pid =fork();
    if(pid<0)
    {
        perror("fork error");
        exit(1);
    }
    if(pid==0){
    void *addr=shmat(shmid,NULL,0);
    char buf[100]="hello world";
    strcpy((char *) addr,buf);
    }
    else if(pid>0)
    {
        void *addr=shmat(shmid,NULL,0);
        if(strlen((char *)addr)>0)
        {
            printf("recv = %s\n",(char *)addr);
        }
        shmdt(addr);
        shmctl(shmid,IPC_RMID,NULL);
    }
    return 0;
}

④信号量(当多个进程/线程进行共享操作时,用于资源保护,以防止出现相互干扰的情况。)

信号量的使用步骤:进程调用semget函数创建新的信号量集合,或者获取已有的信号量集合。--------->调用semctl函数给集合中的每个信号量设置初始值--------->调用semop函数,对集合中的信号量进行pv操作(加锁解锁)---------->调用semctl删除信号量集合

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int main()
{

    pid_t pid;

    key_t key = ftok("/tmp/5", 'p');

    int semid = semget(key, 1, IPC_CREAT | 0644);

    if(semid < 0)
    {
        perror("sem get error!");
        exit(1);
    }
    
    if(semctl(semid,0,SETVAL,1) < 0)
    {
        perror("semctl error!");
        exit(1);
    }

    if ((pid = fork()) < 0)
    {
        perror("frok error!");
        exit(1);
    }

    //b.txt

    if (pid == 0)
    {
        //"hello world\n"

        int fd = open("b.txt", O_WRONLY);
        if (fd == -1)
        {
            perror("open file error!");
            exit(1);
        }
        
        struct sembuf sem;
        sem.sem_num = 0;
        sem.sem_flg = SEM_UNDO;

        while (1)
        {
            //-1  p
            sem.sem_op = -1;
            semop(semid,&sem,1);
            write(fd, "hello", 5);
            write(fd, "world", 5);
            write(fd, "\n", 1);
            sem.sem_op = +1;
            semop(semid,&sem,1);
            //v
            //+1
            //sleep(1);
        }
    }
    else if (pid > 0)
    {
        //"hhhhh wwwww\n"

        int fd = open("b.txt", O_WRONLY);
        if (fd == -1)
        {
            perror("open file error!");
            exit(1);
        }

        struct sembuf sem;
        sem.sem_num = 0;
        sem.sem_flg = SEM_UNDO;

        while (1)
        {
            //-1
            sem.sem_op = -1;
            semop(semid,&sem,1);
            write(fd, "hhhhh", 5);
            write(fd, "wwwww", 5);
            write(fd, "\n", 1);
            sem.sem_op = +1;
            semop(semid,&sem,1);
            //+1
            //sleep(1);
        }
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宋马尧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值