8.5IO进程线程

笔记

进程

三.进程间通信(IPC)

3.1进程间通信的引入

        1> 对于多个线程之间通信,我们可以使用临界资源来完成,通过一个线程任务对临界资源进行修改,另一个线程也可以使用已经修改过的临界资源,但是要注意使用同步互斥机制完成对临界资源的保护

        2> 多个进程之间不能使用全局变量来进行进程间通信,多个进程之间的用户空间是相互独立的,每个进程的全局变量是各个进程独立拥有的,更改一个进程的全局变量,另一个进程不会受到影响,故而不能使用全局变量来完成通信

        3> 使用文件来完成进程间通信是可行的,但是要求写进程先完成向文件中写入数据,然后读进程才能读取数据,必须要加入进程的同步操作

        4> 多个进程之间内核空间是共享的,我们可以通过将数据放入到内核空间,来完成两个进程之间信息的交流

        5> 进程间通信方式:

                        1、内核提供的原始通信方式

                                无名管道 有名管道 信号

                        2、system V提供三种

                                 消息队列 共享内存 信号量集

3.2无名管道

        1> 顾名思义就是没有名字的管道文件,所以只能适用于亲缘进程间的通信

        2> 原理:通过内核,在内存中创建出一个管道文件,存放在内存空间,并不在文件系统中真实存在。当打开该文件时,会返回该文件的两个文件描述符,分别对应读端和写端。可以通过读端从管道中读取数据,从写端向管道中写入数据。当该文件的读写两端全部被关闭后,该管道文件会在内存中消失

        3> 注意:由于打开管道时返回的是文件描述符,所以,对该文件的操作,只能使用文件IO

对于存入管道中的数据的读取是一次性的,当数据读取结束后,数据就不存在于管道文件中了

        4> 无名管道的API接口函数

       #include <unistd.h>

       int pipe(int pipefd[2]);
       功能:在通过内核在内存中创建一个无名管道,并通过参数将该管道文件的两个文件描述符返回
       参数:接收文件描述符的数组,pipefd[0]表示管道文件的读端,pipefd[1]表示管道的写端
       返回值:成功返回0,失败返回-1并置位错误码
3.3有名管道

        1> 顾名思义就是有名字的管道文件,会在文件系统中创建一个有名字的管道文件

        2> 可以用于亲缘进程间的通信,也可以用于非亲缘进程间的通信

        3> 有名管道的API函数

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

       int mkfifo(const char *pathname, mode_t mode);
    功能:在文件系统中创建一个有名管道,但是并没有打开该文件
    参数1:有名管道的名称
    参数2:管道文件的权限
    返回值:成功返回0,失败返回-1并置位错误码
3.4信号通信

1> 信号通信原理图:两个异步通信的进程之间,通过发送相关信号,完成任务间的通信

        2> 信号是linux中软件模拟硬件的“中断”的一种方式。信号是软件部分的名词,中断是硬件部分的名词

        3> 能够发送的信号可以通过指令:kill -l进行查看

        4> 对于信号的处理方式有三种:默认、捕获、忽略

有两个信号既不能被捕获,也不能被忽略:SIGKILL、SIGSTOP

        5> 上面的信号触发条件以及默认处理方式可以通过指令 man 7 signal进行查看

        6> 信号的发送者可以是内核、其他进程、用户自己

        7> 将信号与信号处理方式连接函数

       #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);
       功能:将信号与信号处理函数绑定到一起
       参数1:要绑定的信号
       参数2:信号处理函数
               SIG_IGN:表示忽略信号
               SIG_DFL:表示默认处理
               填自定义函数的入口地址
        返回值:成功返回处理方式的起始地址,失败返回 SIG_ERR
3.5特殊的信号处理

        1> SIGCHLD信号:以非阻塞的形式回收僵尸进程

#include<myhead.h>

//自定义信号处理函数
void handler(int signo)
{
    if(signo == SIGCHLD)
    {
        while(1)
        {
            //判断是否将僵尸进程全部回收了
            if(waitpid(-1, NULL, WNOHANG) == 0)
            {
                break;
            }
        }
    }
}

/******************主程序**********************/
int main(int argc, const char *argv[])
{
    //将SIGCHLD信号与信号处理函数绑定到一起
    if(signal(SIGCHLD, handler) == SIG_ERR)
    {
        perror("signal error");
        return -1;
    }


    for(int i=0; i<10; i++)
    {
        if(fork() == 0)
        {
            exit(EXIT_SUCCESS);
        }
    
    }

    while(1);

    /*
    for(;;)
    {
        printf("我是小妖怪,逍遥游自在\n");
        sleep(1);
    }*/

    return 0;
}

        2> SIGALRM:定时器信号

程序允许启动一个定时器,当所定的时间到位后,会发送一个SIGALRM信号,我们可以将该信号绑定到对应的信号处理函数中,从而导致,给定时间后,处理自定义函数。该信号需要使用一个函数来发送超时信号:alarm闹钟函数

  #include <unistd.h>

       unsigned alarm(unsigned seconds);
    功能:给进程设置一个定时器,以秒为单位,当定时器到位后,后向该进程发送一个SIGALRM的信号
    参数:秒数,如果参数设置成0,表示删除定时器
    返回值:>0:表示返回的上一个定时器剩余的秒数,并且重置上一个定时器
            0:表示之前没有设置定时器
#include<myhead.h>

//定义信号处理函数
void handler(int signo)
{
    if(signo == SIGALRM)
    {
        printf("阎王叫你三更死,怎可留人到五更\n");
        sleep(2);
        exit(EXIT_SUCCESS);
    }
}


/********************主程序******************/
int main(int argc, const char *argv[])
{

    //将SIGALRM信号与信号处理函数绑定
    if(signal(SIGALRM, handler) == SIG_ERR)
    {
        perror("signal error");
        return -1;
    }


    printf("%d\n", alarm(10));          //0

    sleep(5);


    printf("%d\n", alarm(10));          //5


    int count = 0;
    while(1)
    {
        printf("能活一秒是一秒\n");
        sleep(1);
        /*
        count++;
        if(count == 3)
        {
            alarm(0);           //删除定时器
        }
        */
    }

    return 0;
}

        3> 信号的发送函数

       #include <signal.h>

       int kill(pid_t pid, int sig);
       功能:向指定的进程发送指定的信号
       参数1:要发送的进程号
           >0:表示向指定的进程发送信号
           =0:表示向某个进程组(当前进程所在的进程组)中发送信号
           =-1:向所有进程发送信号
           <-1:表示向其他进程组(组id为给定pid的绝对值)发送信号
       参数2:要发送的信号号
       返回值:      成功返回0,失败返回-1并置位错误码
       
       #include <signal.h>

       int raise(int sig);
       功能:向自己所在的进程发送指定的信号
       参数:要发送的信号
       返回值:成功返回0,失败返回非0数字

作业

1> 使用有名管道实现,一个进程用于给另一个进程发消息,另一个进程收到消息后,展示到终端上,并且将消息保存到文件上一份

#include<myhead.h>
int main(int argc, char const *argv[])
{
    if(mkfifo("./fifo",0664)==-1)
    {
        perror("mkfifo error");
        return -1;
    }
    return 0;
}
#include<myhead.h>
int main(int argc, char const *argv[])
{
    int fp=-1;
    if((fp=open("./fifo",O_WRONLY))==-1)
    {
        perror("open fp error");
        return -1;
    }
    char buf[128]="";
    printf("对方已上线\n");
    while(1)
    {
        printf("请输入:\n");
        fgets(buf,sizeof(buf),stdin);
        buf[strlen(buf)-1]=0;
        write(fp,buf,strlen(buf)); 
        if(strcmp(buf,"quit")==0)
        {
            break;
        }
        
    }
    close(fp);
    return 0;
}
#include<myhead.h>
int main(int argc, char const *argv[])
{
    int fp=-1;
    int fd=-1;
    if((fp=open("./fifo",O_RDONLY))==-1)
    {
        perror("open fp error");
        return -1;
    }
    if((fd=open("./1.txt",O_WRONLY|O_APPEND|O_CREAT,0664))==-1)
    {
        perror("open fd error");
        return -1;
    }
    char buf[128]="";
    printf("对方已上线\n");
    while(1)
    {
        bzero(buf,sizeof(buf));
        read(fp,buf,sizeof(buf)); 
        if(strcmp(buf,"quit")==0)
        {
            break;
        }
        printf("输出:%s\n",buf);
        fflush(stdout);
        write(fd,buf,strlen(buf));
    }
    close(fp);
    close(fd);
    return 0;
}

2> 使用有名管道实现两个进程间相互通信

#include<myhead.h>
int main(int argc, char const *argv[])
{
    if(mkfifo("./fifo1",0664)==-1)
    {
        perror("mkfifo error");
        return -1;
    }
    if(mkfifo("./fifo2",0664)==-1)
    {
        perror("mkfifo error");
        return -1;
    }
    return 0;
}
#include<myhead.h>
void*output(void *fd)
{
    int fp=*((int*)fd);
    char sbuf[128]="";
    while(1)
    {  
        bzero(sbuf,sizeof(sbuf));
        read(fp,sbuf,sizeof(sbuf));
        if(strcmp(sbuf,"quit")==0)
        {
            break;
        }
        printf("\t\t\t%s:user2\n",sbuf);
    }
    close(fp);
    pthread_exit(NULL);
}
void*input(void *fd)
{
    int fp=*((int*)fd);
    printf("对方已上线\n");
    char sbuf[128]="";
    while(1)
    {
        usleep(10);
		fgets(sbuf,sizeof(sbuf),stdin);
		sbuf[strlen(sbuf)-1]=0;
		write(fp,sbuf,strlen(sbuf));
		if(strcmp(sbuf,"quit")==0)
		{
			break;
		}
    }
    close(fp);
    pthread_exit(NULL);
} 
int main(int argc, char const *argv[])
{
    int outfd=open("./fifo1",O_RDONLY);
    if(outfd==-1)
    {
        perror("open error");
        return-1;
    }
    int infd=open("./fifo2",O_WRONLY);
    if(infd==-1)
    {
        perror("open error");
        return-1;
    }
    pthread_t tid1=-1;
    if(pthread_create(&tid1,NULL,output,&outfd)!=0)
    {
        printf("pthread_create error\n");
        return-1;
    }
    pthread_t tid2=-1;
    if(pthread_create(&tid2,NULL,input,&infd)!=0)
    {
        printf("pthread_create error\n");
        return-1;
    }
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);

    return 0;
}
#include<myhead.h>
void*output(void *fd)
{
    int fp=*((int*)fd);
    char sbuf[128]="";
    while(1)
    {  
        bzero(sbuf,sizeof(sbuf));
        read(fp,sbuf,sizeof(sbuf));
        if(strcmp(sbuf,"quit")==0)
        {
            break;
        }
        printf("\t\t\t%s:user1\n",sbuf);
    }
    close(fp);
	pthread_exit(NULL);
}
void*input(void *fd)
{
    int fp=*((int*)fd);
    printf("对方已上线\n");
    char sbuf[128]="";
    while(1)
    {
        usleep(10);
		fgets(sbuf,sizeof(sbuf),stdin);
		sbuf[strlen(sbuf)-1]=0;
		write(fp,sbuf,strlen(sbuf));
		if(strcmp(sbuf,"quit")==0)
		{
			break;
		}
    }
    close(fp);
	pthread_exit(NULL);
} 
int main(int argc, char const *argv[])
{
	int infd=open("./fifo1",O_WRONLY);
    if(infd==-1)
    {
        perror("open error");
        return-1;
    }
    int outfd=open("./fifo2",O_RDONLY);
    if(outfd==-1)
    {
        perror("open error");
        return-1;
    }
    
    pthread_t tid1=-1;
    if(pthread_create(&tid1,NULL,output,&outfd)!=0)
    {
        printf("pthread_create error\n");
        return-1;
    }
    pthread_t tid2=-1;
    if(pthread_create(&tid2,NULL,input,&infd)!=0)
    {
        printf("pthread_create error\n");
        return-1;
    }
    pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
    return 0;
}

思维导图

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值