首页 > 系统相关 >IO进程(学习)2024.8.21

IO进程(学习)2024.8.21

时间:2024-08-21 18:53:14浏览次数:10  
标签:IO 21 2024.8 int 管道 fd 信号 进程 include

目录

进程间通信

进程间通信方式

无名管道

特点

读写特性

函数接口

有名管道

特点

函数接口

读写特性

无名管道和有名管道的区别 

信号

信号的概念

信号的分类

信号的处理方式

信号产生的方式

信号

信号函数

发送信号

闹钟信号

进程间通信

进程间通信方式

1..早期的进程间通信方式
        无名管道、有名管道、信号
2.system V IPC对象
        共享内存、信号灯集、消息队列
3.BSD
        socket套接字

无名管道

特点

1..只能用于具有亲缘关系的进程之间的通信
2.半双工的通信模式,具有固定的读端和写端
3.管道可以看成是一种特殊的文件,对于它的读写可以使用文件IO如read、write函数.
4.管道是基于文件描述符的通信方式。当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1]。其中fd[0]固定用于读管道,而fd[1]固定用于写管道。

读写特性

1.当管道中无数据时,读操作会阻塞;管道中无数据时,将写端关闭,读操作会立即返回
2.管道中装满(管道大小64K)数据写阻塞,一旦有4k空间,写继续
3.只有在管道的读端存在时,向管道中写入数据才有意义。否则,会导致管道破裂,向管道中写入数据的进程将收到内核传来的SIGPIPE信号  (通常Broken pipe错误)。Broken pipe:管道破裂

函数接口

#include <unistd.h>
int pipe(int fd[2])
功能:创建无名管道
参数:文件描述符 fd[0]:读端        fd[1]:写端
返回值:成功 0
              失败 -1

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

int main(int argc, char const *argv[])
{
    char a[32] = "";
    char buf[65536] = "";
    char buf1[4096] = "";
    int fd[2] = {0};
    if (pipe(fd) < 0)
    {
        perror("创建管道文件失败");
        return -1;
    }
    printf("%d %d\n", fd[0], fd[1]);

    // 管道破裂
    //  close(fd[0]);
    //  write(fd[1], "hello", 5);
    //  printf("hello world\n");

    // 管道中写满64k数据,继续写会阻塞,需取出4k空间
    //  write(fd[1], buf, 65536);
    //  read(fd[0], buf1, 4096);
    //  write(fd[1], "h", 1);
    //  printf("hello world\n");

    //  读写操作
    //  write(fd[1], "hello", 5);
    //  close(fd[0]);
    //  read(fd[0], a, 32);
    //  printf("%s\n", a);

    //  read(fd[0], a, 32);
    //  printf("%s\n", a);

    return 0;
}

有名管道

特点

1.有名管道可以使互不相关的两个进程互相通信
2.有名管道可以通过路径名来指出,并且在文件系统中可见,但内容存放在内存中
3.进程通过文件IO操作有名管道
4.有名管道遵循先进先出规则
5.不支持如lseek() 操作  

函数接口

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

int mkfifo(const char *filename,mode_t mode);
功能:创健有名管道
参数:filename:有名管道文件名
           mode:权限
返回值:成功:0  
              失败:-1,并设置errno号

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

int main(int argc, char const *argv[])
{
    char buf[32] = "";
    if (mkfifo("fifo", 0666) < 0)
    {
        if (errno == EEXIST)
        {
            printf("mkfifo创建已存在\n");
        }
        else
        {
            printf("mkfifo创建失败");
            return -1;
        }
    }
    else
    {
        printf("mkfifo创建成功\n");
    }

    int fd = open("fifo", O_RDWR);
    if (fd < 0)
    {
        perror("打开文件fifo失败");
        return -1;
    }

    write(fd, "hello", 5);
    read(fd, buf, 32);
    printf("%s\n", buf);

    return 0;
}

读写特性

1.只写方式,写阻塞(阻塞在打开文件的位置),一直到另一个进程把读打开
2.只读方式,读阻塞(阻塞在打开文件的位置),一直到另一个进程把写打开
3.可读可写,如果管道中没有数据,读阻塞

无名管道和有名管道的区别 

无名管道有名管道
使用场景只能用在亲缘关系的进程可以用在不相关的任意进程中
特点

1.有固定的读端和写端

2.使用文件IO进行操作

3.先入先出原则

4.不支持lseek()操作

5.存放在内核空间

1.在文件系统中存在真实的管道文件 

2.使用文件IO进行操作

3.先入先出原则

4.不支持lseek()操作

5.存放在内核空间

操作直接进行读写操作先打开管道文件,再进行读写操作
函数pipe()

mkfifo()

信号

信号的概念

信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式
信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。
如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。

信号的分类

在Linux中,信号被分为不可靠信号和可靠信号,一共64种,可以通过kill -l命令来查看
1.不可靠信号:也称为非实时信号,不支持排队,信号可能会丢失,比如发送多次相同的信号,进程只能收到一次,信号值取值区间为1~31
2.可靠信号:也称为实时信号,支持排队,信号不会丢失,发多少次,就可以收到多少次,信号值取值区间为34~64

信号的处理方式

1.忽略信号:不做任何处理
2.捕捉信号:执行自定义的信号处理函数
3.执行(缺省)默认操作:Linux系统中对每种信号规定了默认操作,即执行信号默认的功能

信号产生的方式

对于前台进程,用户可以输入特殊字符来发送,比如输入 Ctrl c
系统状态变化:比如alarm定时器到期时将引起SIGALRM信号
在终端运行kill命令或在程序中调用kill函数

信号

SIGKILL:结束进程,不能被忽略不能被捕捉        9
SIGSTOP:结束进程,不能被忽略不能被捕捉,停止信号        19  
SIGCHLD:子进程状态改变时给父进程发的信号,不会结束进程        17
SIGINT:结束进程,对应的快捷方式 ctrl c        2 
SIGTSTP:暂停信号,对应的快捷方式 ctrl z        20
SIGQUIT:退出信号,对应的快捷方式 ctrl \        3
SIGALRM:闹钟信号,alarm函数设置定时,当到设定的时间时,内核会向进程发送此信号结束进程        14
SIGTERM:结束终端进程,kill使用时不加数字默认是此信号        15

信号函数

发送信号

#include <signal.h>
int kill(pid_t pid, int sig);
功能:信号发送
参数:pid:指定进程
           sig:要发送的信号
返回值:成功 0     
              失败 -1

int raise(int sig);
功能:进程向自己发送信号
参数:sig:信号
返回值:成功 0   
              失败 -1

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    // kill(getpid(), SIGKILL);
    raise(SIGKILL);
    while (1);
    return 0;
}

闹钟信号

#include <unistd.h>
unsigned int alarm(unsigned int seconds)
功能:在进程中设置一个定时器
参数:seconds:定时时间,单位为秒
返回值:
        如果调用此alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。
注意:一个进程只能有一个闹钟时间。如果在调用alarm时已设置过闹钟时间,则之前的闹钟时间被新值所代替


int pause(void);
功能:用于将调用进程挂起,直到收到信号为止。

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

int main(int argc, char const *argv[])
{
    int n = alarm(3);
    printf("%d\n", n);

    sleep(1);

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

    pause(); // 用于将我们的进程挂起(形成阻塞),直到收到信号为止
    return 0;
}

标签:IO,21,2024.8,int,管道,fd,信号,进程,include
From: https://blog.csdn.net/qq_60450758/article/details/141386328

相关文章