嵌入式系统设计学习周记⑧——进程间通信

进程管理

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

进程实现多任务

特点:给每个进程分配独立的地址空间,4G的大小(1G内核,3G用户空间:栈、堆、数据段、代码段),互不干扰
进程创建方式:fork > exec函数族 > system > vfork
进程的退出:exit()库函数(清理缓存),_exit()系统调用API(不清理缓存)
进程等待:wait():解决僵尸进程
<僵尸进程、孤儿进程、守护进程、控制进程、后台进程>

进程间通信

管道(pipe)

结构简单,只能单向,会发生阻塞,分为无名通道和有名通道
无名通道:只允许具有血缘关系的进程间通信,如父子进程
API: int pipe(int pipefd[2]);
有名通道:允许任意进程间通信
API:i nt mkfifo(const char *pathname,mode_t mode);

#include 
#include 
#include 
#include 
#include 
#include 
#include 
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;
}

消息队列(msg)

消息队列的本质是由内核创建的用于存放消息的链表
特点:传送有格式的消息流;适用于多进程网状交叉通信
组成:消息标号+消息正文
API:
int msgget(key_t key,int msgflg);
int msgsnd(int msqid,const *msgp,size_t msgsz,int msgflg);
ssize_t msgrcv(int msqid, void *msgp,size_t msgsz,long msgtyp,int msgflg);
int msgctl(int msqid,int cmd,struct msqid_ds *buf);

#include 
#include 
#include 
#include 
#include 
#include 
#include 

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;
}

共享内存(shm)

让同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新
特点:减少进行内核空间访问次数;直接使用地址来读写缓存时,效率会更高,适用于大数据量的通信
API:
int shmget(key_t,size_t size,int shmflg)
void *shmat(int shmid,const void *shmaddr,int shmflg)
int shmdt(const void *shmaddr)
int shmctl(int shmid,int cmd,struct shmid_ds *buf)

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main()
{
    pid_t pid;

    key_t key;
    key = ftok("/tmp/kk", 'k');

    int shmid = shmget(key, 1024, IPC_CREAT | 0644);

    if (shmid < 0)
    {
        perror("shm get error!");
        exit(1);
    }

    pid = fork();

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

    if (pid == 0)
    {
        //shmid
        void *addr = shmat(shmid, NULL, 0);
        char buf[100] = {0};
        while (1)
        {
            scanf("%s", buf);
            strcpy((char *)addr, buf);
            sleep(1);
        }
    }
    else if (pid > 0)
    {
        //shmid
        sleep(1);

        void *addr = shmat(shmid, NULL, 0);
        while (1)
        {
            if (strlen((char *)addr) > 0)
            {
                printf("recv = %s\n", (char *)addr);
            }
            else
            {
                printf("no data!");
            }
            sleep(1);
            
        }
    }

    return 0;
}

信号量/锁(sem)

当多个进程/线程进行共享操作时,用于资源保护,以防止出现相互干扰的情况
资源保护的操作:互斥、同步(通过加锁)
对于互斥操作来说,多进程共享操作时,多个进程间不关心谁先操作、谁后操作的先后顺序问题,它们只关心一件事,那就是我在操作时别人不能操作。
所以所谓同步就是,多个共享操作时,进程必须要有统一操作的步调,按照一定的顺序来操作。
信号量分为二值信号量和多值信号量。
API:
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);

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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;
}

你可能感兴趣的:(嵌入式系统设计学习周记⑧——进程间通信)