嵌入式--软件--应用程序--C语言--进程--学习笔记(高级篇-多进程通信篇)

0-- 系列文章目录

1.进程篇:  (进程基础篇)(线程基础篇链接(本文章)

2.网络篇:  (文章链接)

3.数组篇:  (文章链接)

4.指针篇:  (文章链接)

5.内核篇:  (文章链接)

6.硬件篇:  (文章链接)(视频链接)

...........

 1--当前文章目录

  • 前言
  • 一、理论部分
  • 二、实际操作
    • 1.创建子进程(fork)条件变量(等出租车,两线程)
    • 2.线程池概念和创建使用
    • 3.线程间的通信1(无名管道(pipe)
    • 4.线程间的通信2(有名管道 (fifo)
    • 5.线程间的通信3(共享内存(mmap),用的最多)
    • 6.线程间的通信4(信号(signal)
    • 7.线程间的通信5(套接字(socket)详情间网络部分
  • 总结

一.理论部分

理论部分请见线程篇

无名管道:血缘关系的进程,父子进程间,单工通信

有名管道:任意两个,或者以上的进程通信,单工

共享内存:更方便,不必调用read,write这些。可以直接访问内存的方式访问。

信号通信:信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式

                 所有信号的产生及处理全部都是由内核完成的            

        信号的产生:

                1 按键产生

                2 系统调用函数产生(比如raise, kill)

                3 硬件异常

                4 命令行产生 (kill)

                5 软件条件(比如被0除,访问非法内存等)

        信号处理方式:

                1 缺省方式

                2 忽略信号

                3 捕捉信号

套接字法:详情请见网络部分用的最多

二.实际操作

1、条件变量(等出租车,两线程)

应用场景:生产者消费者问题,是线程同步的一种手段。

必要性:为了实现等待某个资源,让线程休眠。提高运行效率

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>


pthread_cond_t  hasTaxi=PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock  = PTHREAD_MUTEX_INITIALIZER;


struct taxi{
    struct taxi *next;
    int num;

};

struct taxi *Head=NULL;

void *taxiarv(void *arg){
    printf("taxi arrived thread\n");
    pthread_detach(pthread_self());
    struct taxi *tx;
    int i=1;
    
    while(1){
        tx = malloc(sizeof(struct taxi));
        tx->num = i++;
        printf("taxi %d comming\n",tx->num);
        pthread_mutex_lock(&lock);
        tx->next = Head;
        Head = tx;
        pthread_cond_signal(&hasTaxi);
        //pthread_cond_broadcast(&hasTaxi);
        pthread_mutex_unlock(&lock);
        sleep(1);
    }
    pthread_exit(0);
}

void *takeTaxi(void *arg){
    printf("take taxi thread\n");
    pthread_detach(pthread_self());
    struct taxi *tx;

    while(1){
        pthread_mutex_lock(&lock);
        while(Head==NULL)
        {
            pthread_cond_wait(&hasTaxi,&lock);
        }
        tx = Head;
        Head=tx->next;
        printf("%d,Take taxi %d\n",(int)arg,tx->num);
        free(tx);
        pthread_mutex_unlock(&lock);
    }
    pthread_exit(0);
}

int main(){
    pthread_t tid1,tid2,tid3;

    pthread_create(&tid1,NULL,taxiarv,NULL);
//    sleep(5);
    pthread_create(&tid2,NULL,takeTaxi,(void*)1);
    pthread_create(&tid2,NULL,takeTaxi,(void*)2);
    pthread_create(&tid3,NULL,takeTaxi,(void*)3);

    while(1) {
        sleep(1);

    }


}

线程池概念和创建使用

概念:

通俗的讲就是一个线程的池子,可以循环的完成任务的一组线程集合

必要性:

我们平时创建一个线程,完成某一个任务,等待线程的退出。但当需要创建大量的线程时,假设T1创建线程时间,T2为在线程任务执行时间,T3线程销毁时间当 T1+T3 > T2,这时候就不划算了,使用线程池可以降低频繁创建和销毁线程所带来的开销,任务处理时间比较短的时候这个好处非常显著

线程池的基本结构:

1 任务队列,存储需要处理的任务,由工作线程来处理这些任务

2 线程池工作线程,它是任务队列任务的消费者,等待新任务的信号

 

 创建五步走(创建线程池的基本结构,线程池的初始化,线程池添加任务,实现工作线程,线程池的销毁

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#define POOL_NUM 10
typedef struct Task{
    void *(*func)(void *arg);
    void *arg;
    struct Task *next;
}Task;

typedef struct ThreadPool{
    pthread_mutex_t taskLock;
    pthread_cond_t newTask;

    pthread_t tid[POOL_NUM];
    Task *queue_head;
    int busywork;

}ThreadPool;
ThreadPool *pool;


void *workThread(void *arg){
    while(1){
        pthread_mutex_lock(&pool->taskLock);
        pthread_cond_wait(&pool->newTask,&pool->taskLock);

        Task *ptask = pool->queue_head;
        pool->queue_head = pool->queue_head->next;

        pthread_mutex_unlock(&pool->taskLock);

        ptask->func(ptask->arg);
        pool->busywork--;


    }


}

void *realwork(void *arg){
    printf("Finish work %d\n",(int)arg);

}

void pool_add_task(int arg){
    Task *newTask;
    
    pthread_mutex_lock(&pool->taskLock);
    while(pool->busywork>=POOL_NUM){
        pthread_mutex_unlock(&pool->taskLock);
        usleep(10000);
        pthread_mutex_lock(&pool->taskLock);
    }
    pthread_mutex_unlock(&pool->taskLock);
    

    newTask = malloc(sizeof(Task));
    newTask->func =  realwork;
    newTask->arg = arg;
    

    pthread_mutex_lock(&pool->taskLock);
    Task *member = pool->queue_head;
    if(member==NULL){
        pool->queue_head = newTask;
    }else{
       while(member->next!=NULL){
            member=member->next;
       }
       member->next = newTask;

    }
    pool->busywork++;
    pthread_cond_signal(&pool->newTask);

    pthread_mutex_unlock(&pool->taskLock);


}


void pool_init(){
    pool = malloc(sizeof(ThreadPool));
    pthread_mutex_init(&pool->taskLock,NULL);
    pthread_cond_init(&pool->newTask,NULL);
    pool->queue_head = NULL;
    pool->busywork=0;

    for(int i=0;i<POOL_NUM;i++){
        pthread_create(&pool->tid[i],NULL,workThread,NULL);
    }
}

void pool_destory(){
    Task *head;
    while(pool->queue_head!=NULL){
        head = pool->queue_head;
        pool->queue_head = pool->queue_head->next;
        free(head);
    }

    pthread_mutex_destroy(&pool->taskLock);
    pthread_cond_destroy(&pool->newTask);
    free(pool);

}
int main(){
   pool_init();
   sleep(20);
   for(int i=1;i<=20;i++){
       pool_add_task(i);

   }

   sleep(5);
   pool_destory();

}

(3)无名管道

  1. 只能用于亲缘关系的进程间通信(父子进程,兄弟进程)
  2. 管道通信是单工的,一端读,一端写(程序实现设计好)
  3. 数据自己读不能自己写
  4. 管道可以用于大于2个进程共享
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(){
    int pfd[2];
    int re;
    char buf[20]={0};
    pid_t pid;
    re = pipe(pfd);
    if(re<0){
        perror("pipe");
        return 0;
    }
    printf("%d,%d\n",pfd[0],pfd[1]);
    pid = fork();
    if(pid<0){
        perror("fork");
        return 0;
    }else if(pid>0){
        //close(pfd[0]);
        while(1){
            strcpy(buf,"hhahahahah");
            write(pfd[1],buf,strlen(buf));

            sleep(1);
        }

    }else{
        close(pfd[1]);        
       while(1){
            re=read(pfd[0],buf,20);
            if(re>0){
                printf("read pipe=%s\n",buf);
            }    
        }
    }


}

  一个父进程读,两个子进程写入(时间错开一点点)

#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(){
    int pfd[2];
    int i;
    int re;
    char buf[40]={0};
    pid_t pid;
    re = pipe(pfd);
    if(re<0){
        perror("pipe");
        return 0;
    }
    printf("%d,%d\n",pfd[0],pfd[1]);

    for(i=0;i<2;i++){
        pid = fork();
        if(pid<0){
            perror("fork");
            return 0;
        }else if(pid>0){

        }else{
            break;   
            
        }
    }
    if(i==2){
        close(pfd[1]);
        while(1){
            memset(buf,0,40);
            re=read(pfd[0],buf,40);
            if(re>0){
                printf("%s\n",buf);
            }    
        }
        return 0;
    }

    if(i==1){
        close(pfd[0]);
        while(1){
            strcpy(buf,"this is 2 process");
            write(pfd[1],buf,strlen(buf));
            usleep(930000);
        }
        return 0;
    }
    if(i==0){
        close(pfd[0]);
        while(1){
            strcpy(buf,"this is 1 process");
            write(pfd[1],buf,strlen(buf));
            sleep(1);
        }

        return 0;
    }


}

(4) 有名管道(命名管道,FIFO,先进先出)

 有名管道可以使非亲缘的两个进程互相通信

 通过路径名来操作,在文件系统中可见,但内容存放在内存中

 文件IO来操作有名管道(创建是创建文件)

 不支持leek操作

 单工读写

两个文件(一个读,,一个写)

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


int main(){
    int re;
    int fd;
    char buf[32];

    re = mkfifo("/myfifo",0666);
    if(re<0){
        perror("mkfifo");
        //return 0;
    }


    fd = open("/myfifo",O_WRONLY|O_NONBLOCK);
    if(fd<0){
        perror("open");
        return 0;
    }

    
    printf("after open\n");
    while(1){
        fgets(buf,32,stdin);
        write(fd,buf,strlen(buf));

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


int main(){
    int re;
    int fd;
    char buf[32];
/*
    re = mkfifo("/myfifo",0666);
    if(re<0){
        perror("mkfifo");
        return 0;
    }
    */
    fd = open("/myfifo",O_RDONLY);
    if(fd<0){
        perror("open");
        return 0;
    }
    printf("after open\n");

    
    while(1){
        
        re=read(fd,buf,32);
        if(re>0){
            printf("read fifo=%s\n",buf);
        }else if(re==0){
            exit(0);
        }

    }
}

(5)进程的通信--共享内存(mmap

实现了用户空间和内核空间的高效交互方式(mmap)
(两个程序一个写,一个读)
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


int main(){
    
    void *addr;
    int fd;
    fd =open("test",O_RDWR);
    if(fd<0){
        perror("open");
        return 0;
    }
    int len = lseek(fd,0,SEEK_END);    
    addr = mmap(NULL,2048, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if(addr == MAP_FAILED){
        perror("mmap");
        return 0;
    }
    close(fd);


//    memcpy((addr),"99999999999999",15);
    while(1){
        printf("read=%s\n",(char*)(addr));
        sleep(1);
    }
}
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


int main(){
    
    void *addr;
    int fd;
    fd =open("test",O_RDWR);
    if(fd<0){
        perror("open");
        return 0;
    }
    int len = lseek(fd,0,SEEK_END);    
    addr = mmap(NULL,2048, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if(addr == MAP_FAILED){
        perror("mmap");
        return 0;
    }
    close(fd);


    int i=0;
    while(i<2048){
        memcpy((addr+i),"a",1);
        i++;
        sleep(1);
    }    
//    printf("read=%s\n",(char*)(addr));

}

 

 父子进程间通信

#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(){

    void *addr;
    
    addr = mmap(NULL,2048, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
    if(addr == MAP_FAILED){
        perror("mmap");
        return 0;
    }
    pid_t pid;
    pid = fork();

    if(pid<0){
        perror("fork");
        return 0;
    }
    else if(pid>0){
        memcpy(addr,"1234567890",10);
         
        wait(NULL);
    }else {
        sleep(1);
        printf("read father val=%s\n",(char *)addr);
    }
    
    munmap(addr,2048);     //释放内存

}

(6)信号机制(中断类似)

 抱歉,暂时不太想写,等日后补全。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值