进程间通信-信号-pipe-fifo(课上测试)

一.运行结果

二.代码说明

consumer.c

该程序是一个使用FIFO(命名管道)进行进程间通信的示例。首先定义了FIFO的名称和缓冲区的大小。然后在主函数中,打开了一个以只读方式打开的FIFO,并读取FIFO中的数据直到读取完毕,最后关闭FIFO。

相关系统调用说明:
1. open:打开FIFO文件,返回文件描述符。
2. read:从FIFO中读取数据,将数据存储到指定的缓冲区中。
3. close:关闭FIFO文件。

其他系统调用:
1. getpid:获取当前进程的进程ID。
2. memset:将指定内存区域的前n个字节设置为特定的值。
3. printf:打印格式化输出。
4. exit:退出当前进程。

 

prodecer.c

该程序是一个使用FIFO(命名管道)进行进程间通信的示例。程序首先定义了FIFO的名称、缓冲区的大小和一个10兆字节的常量。然后在主函数中,程序首先检查FIFO是否存在,如果不存在则创建一个FIFO,并以只写方式打开FIFO,然后向FIFO中写入数据,直到写入了10兆字节的数据,最后关闭FIFO。

相关系统调用说明:
1. access:检查文件是否存在。
2. mkfifo:创建一个FIFO文件。
3. open:打开FIFO文件,返回文件描述符。
4. write:向FIFO中写入数据。

其他系统调用:
1. getpid:获取当前进程的进程ID。
2. fprintf:将格式化的数据输出到流中。
3. exit:退出当前进程。

值得注意的是,程序中使用了一个while循环来确保写入了10兆字节的数据,这可能会导致程序在写入完毕前阻塞。

 

testmf.c

该程序是一个创建FIFO(命名管道)的示例。程序中使用了mkfifo系统调用来创建一个FIFO文件,其中指定了FIFO的名称和访问权限。如果mkfifo调用成功,则打印"FIFO created",并以成功的状态码退出程序。

相关系统调用说明:
1. mkfifo:创建一个FIFO文件。

其他系统调用:
1. printf:打印格式化输出。
2. exit:退出当前进程。

 

listargs.c

相关函数说明:

  1. printf:打印格式化输出。
  2. fprintf:将格式化的数据输出到流中。
  3. stderr:标准错误流。

 

pipe.c

这段代码是一个简单的C程序,它使用系统调用来创建管道并执行两个命令。下面是代码中涉及的系统调用的说明:

1. `pipe(thepipe)`: 这个系统调用创建了一个管道,它接受一个整型数组作为参数,数组的两个元素分别代表管道的读端和写端。如果调用成功,将返回0;如果失败,将返回-1。

2. `fork()`: 这个系统调用创建了一个新的进程,新进程是调用进程的副本。在父进程中,`fork()`返回新创建子进程的进程ID;在子进程中,`fork()`返回0;如果出现错误,`fork()`返回-1。

3. `close(fd)`: 这个系统调用关闭一个文件描述符,其中`fd`是要关闭的文件描述符。

4. `dup2(oldfd, newfd)`: 这个系统调用复制文件描述符,将`oldfd`复制为`newfd`。如果`newfd`已经打开,则会先关闭它。如果复制成功,`dup2()`返回新的文件描述符;如果失败,返回-1。

5. `execlp(path, arg0, arg1, ..., argn, (char *)0)`: 这个系统调用用于执行一个新的程序。它接受一个程序路径`path`和一系列参数`arg0`到`argn`,以及一个以`(char *)0`结尾的空指针。如果调用成功,当前进程的内存映像将被新的程序替换,而且不会返回;如果调用失败,将返回-1。

6. `perror(s)`: 这个函数用于输出上一个系统调用的错误消息,消息将包含字符串`s`指定的自定义消息。

7. `exit(status)`: 这个函数终止进程的执行,并返回一个整数值`status`给操作系统。通常,0表示成功,非0表示失败。

以上是代码中使用的主要系统调用和函数,它们用于创建管道、执行命令、关闭文件描述符以及处理错误。

 

pipedemo.c

这段代码是一个简单的C程序,它创建了一个管道,然后从标准输入读取数据,将数据写入管道,再从管道读取数据并将其写入标准输出。下面是代码中涉及的系统调用的说明:

1. `pipe(apipe)`: 这个系统调用创建了一个管道,它接受一个整型数组`apipe`作为参数,数组的两个元素分别代表管道的读端和写端。如果调用成功,将返回0;如果失败,将返回-1。

2. `write(fd, buf, count)`: 这个系统调用用于将数据从缓冲区`buf`写入文件描述符`fd`指定的文件中,写入的字节数由`count`指定。如果调用成功,将返回实际写入的字节数;如果失败,将返回-1。

3. `read(fd, buf, count)`: 这个系统调用用于从文件描述符`fd`指定的文件中读取数据,最多读取`count`个字节,并将其存放到缓冲区`buf`中。如果调用成功,将返回实际读取的字节数;如果失败,将返回-1。

4. `perror(s)`: 这个函数用于输出上一个系统调用的错误消息,消息将包含字符串`s`指定的自定义消息。

5. `exit(status)`: 这个函数终止进程的执行,并返回一个整数值`status`给操作系统。通常,0表示成功,非0表示失败。

在代码中,首先创建了一个管道,然后进入一个循环,不断从标准输入读取数据,将数据写入管道,再从管道读取数据并将其写入标准输出。在每一步操作中,都有相应的错误处理逻辑,以确保程序能够正确地处理数据和错误。

 

whotofile.c

这段代码是一个简单的C程序,它使用了`fork`、`close`、`creat`、`execlp`和`wait`等系统调用来创建子进程,关闭标准输出,将`who`命令的输出重定向到文件`userlist`,然后等待子进程结束。下面是代码中涉及的系统调用的说明:

1. `fork()`: 这个系统调用用于创建一个新的进程,如果调用成功,在父进程中返回子进程的进程ID,在子进程中返回0;如果失败,返回-1。

2. `close(fd)`: 这个系统调用关闭文件描述符`fd`指定的文件。

3. `creat(path, mode)`: 这个系统调用创建一个新文件,如果文件已经存在,则截断它的长度为0。它接受一个字符串`path`作为参数,表示文件路径,以及一个八进制数`mode`表示文件权限。

4. `execlp(file, arg0, arg1, ..., argn, (char *)0)`: 这个系统调用用于执行一个新的程序,它接受一个程序路径`file`和一系列参数`arg0`到`argn`,以及一个以`(char *)0`结尾的空指针。如果调用成功,当前进程的内存映像将被新的程序替换,而且不会返回;如果调用失败,将返回-1。

5. `wait(status)`: 这个系统调用挂起当前进程的执行,直到它的子进程结束。如果调用成功,将返回子进程的进程ID;如果失败,将返回-1。

在代码中,首先使用`fork`创建了一个子进程,子进程关闭了标准输出,然后使用`creat`创建了一个文件`userlist`,接着使用`execlp`执行了`who`命令,并将输出重定向到文件`userlist`,最后使用`wait`等待子进程结束。如果一切顺利,父进程将输出一条消息表示`who`命令已经执行完毕。

这段代码的功能是将`who`命令的输出写入到文件`userlist`中,类似于在终端中执行`who > userlist`的操作。

 

sigactdemo.c

在这段代码中,主要是使用了信号处理相关的系统调用,包括`sigaction`、`sigemptyset`、`sigaddset`等。

1. `sigaction(signum, new_action, old_action)`: 这个系统调用用于设置对信号`signum`的处理方式。`new_action`是一个`struct sigaction`类型的结构体,用于指定信号处理函数、标志等信息。`old_action`是一个可选的指针,用于获取之前对该信号的处理方式。

2. `sigemptyset(set)`: 这个系统调用用于初始化一个信号集`set`,将其置空。

3. `sigaddset(set, signum)`: 这个系统调用用于向信号集`set`中添加信号`signum`。

在代码中,首先定义了一个信号处理函数`inthandler`,然后使用`sigaction`设置了对`SIGINT`信号的处理方式。在处理方式中,指定了当收到`SIGINT`信号时调用`inthandler`函数,同时设置了一些标志位。然后进入一个无限循环,不断从标准输入读取数据并输出。当收到`SIGINT`信号时,将调用`inthandler`函数进行处理。

需要注意的是,`inthandler`函数中调用了`sleep`函数来模拟一个耗时的处理过程。

在代码中也存在一些问题,例如`newhandler`结构体中的`sa_flags`成员缺少分号,应该是`SA_RESTART|SA_NODEFER|SA_RESETHAND;`。另外,对`sigaction`的调用没有进行错误处理,应该检查其返回值来判断是否调用成功。

总的来说,这段代码的功能是设置对`SIGINT`信号的处理方式,当收到`SIGINT`信号时调用`inthandler`函数进行处理。

 

sigdemo.c

这段代码使用了`signal`函数来设置对`SIGINT`信号的处理方式,然后进入一个循环,在循环中输出"hello"并休眠2秒。当收到`SIGINT`信号时,将调用`f`函数来处理信号。

`signal`函数的原型是`void (*signal(int signum, void (*handler)(int)))(int)`,它用于设置对特定信号的处理方式。在这段代码中,`signal(SIGINT, f)`的意思是当收到`SIGINT`信号时,调用`f`函数来处理。

需要注意的是,`signal`函数在不同的系统中可能有不同的行为,因此在实际编程中可能会使用`sigaction`函数来代替`signal`函数,以获得更好的可移植性和更多的功能。

总的来说,这段代码的功能是在循环中输出"hello",每次输出后休眠2秒,同时设置了对`SIGINT`信号的处理方式,当收到`SIGINT`信号时输出"OUCH!"。

posted @ 2023-12-09 19:23  20211329史雨洁  阅读(19)  评论(0编辑  收藏  举报