进程间通信-信号-pipe-fifo
编译fifo文件夹的程序
运行fifo文件夹的程序
代码说明
1.consumer.c 文件包含一个用来从 FIFO(命名管道)读取数据的 C 程序。以下是它的主要组件和系统调用的分解:
main() 函数:
- 初始化文件描述符(pipe_fd)、返回状态(res)、读取数据的缓冲区以及字节数计数(bytes)的变量。
- 设置 FIFO 以只读模式(O_RDONLY)打开。
- 使用 open() 系统调用以指定的模式和路径打开 FIFO。
- 使用循环从 FIFO 读取数据:
- 使用 read() 系统调用从 pipe_fd 读取数据到 buffer。读取的量存储在 res 中。
- 它持续读取直到没有更多数据(res 变为 0)。
- 在读取完成后使用 close() 系统调用关闭 FIFO。
- 如果打开 FIFO 失败,程序以 EXIT_FAILURE 退出。
- 程序在成功退出前打印进程 ID 和读取的数据量。
- 这个程序作为 IPC(进程间通信)场景中的消费者,通过 FIFO 读取生产者进程发送的数据。使用 FIFO 允许进程之间的同步通信。
2.producer.c 文件是一个用于向 FIFO(命名管道)写入数据的 C 程序。以下是其主要组件和系统调用的分析:
main() 函数:
- 初始化文件描述符(pipe_fd)、返回状态(res)、只写模式(O_WRONLY)、字节数计数(bytes)以及数据缓冲区(buffer)。
- 检查 FIFO 是否存在(使用 access() 函数)。如果不存在,则创建一个新的 FIFO(使用 mkfifo())。
- 以只写模式打开 FIFO(使用 open() 系统调用)。
- 使用循环向 FIFO 写入数据:
- 使用 write() 系统调用将 buffer 中的数据写入 pipe_fd。写入的量存储在 res 中。
- 循环直到写入的总量达到 10MB。
- 如果写入过程中出现错误(res 等于 -1),则打印错误信息并退出。
- 关闭 FIFO(使用 close() 系统调用)。
- 如果打开 FIFO 失败,程序以 EXIT_FAILURE 退出。
- 程序在成功退出前打印进程 ID。
- 这个程序充当 IPC 场景中的生产者,通过 FIFO 向消费者进程发送数据。通过检查和创建 FIFO,以及循环写入数据,它与消费者进程协调同步通信。
3.testmf.c 文件是一个简单的 C 程序,用于创建 FIFO(命名管道)。以下是其主要组件的分析:
main() 函数:
- 使用 mkfifo() 系统调用创建一个新的 FIFO。FIFO 的路径被设定为 /tmp/myfifo,权限设置为 0777(意味着任何用户都可以读写该 FIFO)。
- mkfifo() 返回的结果存储在变量 res 中。如果 res 为 0,表示 FIFO 创建成功,程序会打印一条消息确认 FIFO 已创建。
- 程序使用 exit(EXIT_SUCCESS) 退出,表明正常终止。
- 这个程序的作用是创建一个命名管道,它允许 producer.c 和 consumer.c 中的进程进行通信。在 IPC 场景中,通常需要一个独立的程序或进程来创建共享的通信资源(如 FIFO),testmf.c 就承担了这个角色
综上,这三个程序共同构成了一个使用 FIFO 进行进程间通信的示例。testmf.c 负责创建 FIFO,producer.c 将数据写入 FIFO,而 consumer.c 则从 FIFO 读取数据。通过这种方式,两个进程可以安全地共享数据。
编译pipe文件夹下的程序
运行pipe文件夹下的程序
pipe文件夹代码说明
1.listargs.c 是一个用于演示命令行参数处理和标准错误输出的简单 C 程序。
功能:
- 打印命令行参数的数量和每个参数的值。
- 向标准错误流(stderr)输出一条消息。
代码结构:
- main 函数接收两个参数:ac(参数个数)和 av(参数值数组)。
- 使用 printf 输出参数个数(ac)和每个参数的值(通过遍历 av 数组)。
- 使用 fprintf 将消息发送到标准错误流(stderr)。
2.分析 pipe.c
pipe.c 是一个演示如何在 C 程序中创建管道和进程分叉(forking)的程序。
功能:
- 创建一个管道,然后创建一个子进程。
- 子进程和父进程使用这个管道进行通信。
- 父进程执行命令行中的第二个参数作为程序,子进程执行第一个参数作为程序。
代码结构:
- 检查命令行参数的个数,如果不是 3(程序名和两个命令),则显示用法信息并退出。
- 使用 pipe() 创建一个管道。
- 使用 fork() 创建一个子进程。
- 在父进程(pid > 0)中:
- 关闭管道的写端。
- 使用 dup2() 将标准输入重定向到管道的读端。
- 执行 av[2] 指定的程序。
- 在子进程(pid == 0)中:
- 关闭管道的读端。
- 使用 dup2() 将标准输出重定向到管道的写端。
- 执行 av[1] 指定的程序。
- 如果任何步骤失败,使用 oops() 函数打印错误信息并退出。
3.分析 pipedemo.c
pipedemo.c 是一个展示如何在 C 程序中使用管道进行数据读写的程序。
功能:
- 创建一个管道,然后在一个循环中使用这个管道来读写数据。
- 从标准输入(stdin)读取数据,写入管道的写端。
- 从管道的读端读取数据,然后写入标准输出(stdout)。
代码结构:
- 使用 pipe() 创建一个管道。
- 在一个循环中:
- 使用 fgets() 从标准输入读取数据到 buf。
- 使用 write() 将 buf 中的数据写入管道的写端。
- 将 buf 中的所有字符替换为 'X'。
- 使用 read() 从管道的读端读取数据回到 buf。
- 将读取到的数据写入标准输出。
- 如果任何读写操作失败,打印错误信息并跳出循环。
3.分析 pipedemo2.c
pipedemo2.c 是一个演示如何在 C 程序中使用管道进行父子进程通信的程序。
功能:
- 创建一个管道,并通过 fork() 创建一个子进程。
- 子进程定期向管道写入一条消息。
- 父进程定期从管道读取消息并将其写入标准输出。
代码结构:
- 使用 pipe() 创建一个管道。
- 使用 fork() 分叉进程:
- 在子进程(fork() 返回 0)中:
- 无限循环,定期向管道写入 CHILD_MESS(“I want a cookie\n”)。
- 使用 sleep(5) 暂停 5 秒。
- 在父进程(fork() 返回子进程的 PID)中:
- 无限循环,定期向管道写入 PAR_MESS(“testing..\n”)。
- 使用 sleep(1) 暂停 1 秒。
- 从管道读取数据,并将其写入标准输出。
- 如果任何读写操作失败,使用 oops() 函数打印错误信息并退出。
4.分析 stdinredir1.c
stdinredir1.c 是一个演示如何在 C 程序中重定向标准输入(stdin)的程序。
功能:
- 读取并打印来自标准输入的三行文本。
- 关闭当前的标准输入流(文件描述符 0)。
- 打开 /etc/passwd 文件,并将其文件描述符重定向到标准输入。
- 再次读取并打印三行文本,这次是从 /etc/passwd 文件中读取。
代码结构:
- 使用 fgets() 三次从标准输入读取文本行并打印。
- 使用 close(0) 关闭当前的标准输入。
- 使用 open("/etc/passwd", O_RDONLY) 打开 /etc/passwd 文件,并确保它的文件描述符为 0(即标准输入)。
- 如果文件描述符不是 0,则打印错误信息并退出。
- 再次使用 fgets() 三次从新的标准输入(现在是 /etc/passwd 文件)读取文本行并打印。
5.分析 testtty.c
testtty.c 是一个非常简单的 C 程序,用于演示向标准输入(通常是终端)写入数据。
功能:
- 向文件描述符 0(通常是标准输入)写入字符串 "abcde\n"。
代码结构:
- 定义一个字符串 buf,内容为 "abcde\n"。
- 使用 write() 函数向文件描述符 0 写入 buf 中的内容。
编译signal文件夹下的程序
运行signal文件夹下的程序
对上述代码进行解释
第一个文件 sigactdemo.c 包含了一个简单的信号处理示例程序。
- 引入头文件:程序包括标准输入输出库 stdio.h、Unix标准函数库 unistd.h 和信号处理库 signal.h。
- 定义常量:INPUTLEN 被定义为100,可能用于定义输入缓冲区的大小。
- 信号处理函数:定义了一个名为 inthandler 的函数,该函数接受一个整数参数(通常是信号编号),打印接收到的信号,然后休眠一段时间,最后再次打印。
- 主函数 (main):
- 初始化 sigaction 结构体 newhandler,用于指定信号处理行为。
- 设置 newhandler 的处理函数为 inthandler。
- 设置 newhandler 的标志,包括 SA_RESTART(重新启动被信号打断的系统调用)、SA_NODEFER(在处理当前信号时不阻塞当前信号)、SA_RESETHAND(处理完信号后重置信号处理器为默认)。
- 初始化一个信号集 blocked,并将 SIGQUIT 信号加入到这个集合中。这个集合被设置为 newhandler 的信号掩码,意味着在处理 SIGINT 信号时,SIGQUIT 信号会被阻塞。
- 调用 sigaction 函数将 SIGINT(通常是通过Ctrl+C产生)的处理方式设置为 newhandler。
- 程序进入一个无限循环,不断地读取输入并打印。
- 这个程序演示了如何使用 sigaction 结构体和相关函数来处理信号。当用户按下 Ctrl+C 时,会触发 SIGINT 信号,程序会调用 inthandler 函数来处理该信号。在处理信号的过程中,SIGQUIT 信号会被阻塞。
第二个文件 sigactdemo2.c 包含了一个使用信号来实现睡眠功能的程序。程序的主要内容如下:
- 引入头文件:程序包括 Unix 标准函数库 unistd.h、信号处理库 signal.h 和标准输入输出库 stdio.h。
- 信号处理函数:定义了一个名为 sig_alrm 的函数,这个函数没有实际操作(空函数体),用于捕获 SIGALRM 信号。
- 自定义的睡眠函数 (mysleep):
- 接受一个表示秒数的参数 nsecs。
- 定义和设置一个 sigaction 结构体 newact,用于指定 SIGALRM 信号的处理行为(在这里是 sig_alrm 函数)。
- 调用 alarm 函数来设置一个定时器,当定时器到达指定的秒数时,会发送 SIGALRM 信号。
- 调用 pause 函数使进程暂停,直到捕获到一个信号。
- 当 SIGALRM 被捕获后,pause 返回,mysleep 函数再次调用 alarm 函数以获取剩余的睡眠时间。
- 最后,将 SIGALRM 的处理方式恢复为原始状态,并返回未睡足的时间。
- 主函数 (main):
- 使用无限循环,每两秒打印一次信息,演示 mysleep 函数的使用。
- 这个程序展示了如何结合信号处理和 alarm 函数实现一个简单的睡眠机制。当 alarm 计时器触发 SIGALRM 信号时,由于 sig_alrm 函数不执行任何操作,所以程序继续执行,从 pause 返回。
第三个文件 sigdemo1.c 包含了一个基本的信号处理示例程序。这个程序的主要内容包括:
- 引入头文件:程序包括标准输入输出库 stdio.h 和信号处理库 signal.h。
- 信号处理函数:定义了一个名为 f 的函数,该函数接受一个信号编号参数,并在被调用时打印 "OUCH!"。
- 主函数 (main):
- 使用 signal 函数将 SIGINT 信号(通常由 Ctrl+C 触发)的处理方式设置为 f 函数。
- 进入一个循环,循环五次,每次循环打印 "hello" 并休眠两秒。
- 这个程序是对信号处理的一个非常基础的演示。当用户在程序运行时按下 Ctrl+C,SIGINT 信号被触发,程序调用 f 函数来处理这个信号,从而打印 "OUCH!"。。
第四个文件 sigdemo2.c 展示了如何忽略一个信号。这个程序的主要内容如下:
- 引入头文件:程序包括标准输入输出库 stdio.h 和信号处理库 signal.h。
- 主函数 (main):
- 使用 signal 函数将 SIGINT 信号(通常由 Ctrl+C 触发)的处理方式设置为 SIG_IGN,意味着程序将忽略这个信号。
- 打印 "you can't stop me!",然后进入一个无限循环。
- 在循环中,每秒休眠一次,并打印 "haha"。
- 这个程序通过将 SIGINT 信号的处理方式设置为 SIG_IGN,展示了如何使程序对 Ctrl+C 忽视不理。由于这种设置,当用户尝试使用 Ctrl+C 中断程序时,程序将不会响应,而是继续运行并每秒打印 "haha"。
第五个文件 sigdemo3.c 展示了如何处理多种信号。这个程序的主要内容包括:
- 引入头文件:程序包括标准输入输出库 stdio.h、字符串处理库 string.h、信号处理库 signal.h 和 Unix 标准函数库 unistd.h。
- 定义常量:INPUTLEN 被定义为100,用于定义输入缓冲区的大小。
- 信号处理函数:定义了两个处理函数 inthandler 和 quithandler,这两个函数在接收到信号时打印信息,休眠一段时间,然后再次打印。
- 主函数 (main):
- 使用 signal 函数分别将 SIGINT(通常由 Ctrl+C 触发)和 SIGQUIT(通常由 Ctrl+\ 触发)的处理方式设置为 inthandler 和 quithandler。
- 进入一个循环,提示用户输入消息,并使用 read 函数读取输入。
- 如果读取到的字符数为 -1,则打印错误信息;否则打印用户输入的内容。
- 当用户输入的内容以 "quit" 开头时,程序退出循环并结束。
- 这个程序演示了如何为不同的信号设置不同的处理函数。用户在程序运行时可以通过发送特定的信号(如 Ctrl+C 或 Ctrl+\)来触发相应的处理函数。同时,它还提供了一个简单的用户交互方式,允许用户通过输入来控制程序流程。