From 85e2fc451ef477d48e876a19e1ff48845dcf0389 Mon Sep 17 00:00:00 2001 From: flykhan Date: Thu, 17 Aug 2023 09:20:18 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=9B=E7=A8=8B=EF=BC=88=E4=B8=8B=EF=BC=89?= =?UTF-8?q?=EF=BC=8C=E4=BF=A1=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 220 ++++++++++++++++++++++++++++++ day3/d1.c | 11 ++ day3/d10.c | 11 ++ day3/d2.c | 33 +++++ day3/d3.c | 40 ++++++ day3/d4.c | 28 ++++ day3/d5.c | 35 +++++ day3/d5_2.c | 42 ++++++ day3/d6.c | 21 +++ day3/d7.c | 15 ++ day3/d8.c | 15 ++ day3/signal_other/test_sigset_t.c | 48 +++++++ day3/t11.c | 15 ++ day3/t12.c | 19 +++ day3/t13.c | 28 ++++ day3/t14.c | 25 ++++ day3/t15.c | 35 +++++ day3/t16.c | 16 +++ day3/t17.c | 16 +++ day3/t18.c | 18 +++ day3/t19.c | 30 ++++ day3/t20.c | 48 +++++++ day3/t21.c | 47 +++++++ day3/test_execve.c | 11 ++ day3/test_pause.c | 31 +++++ day3/test_sigaction.c | 38 ++++++ 26 files changed, 896 insertions(+) create mode 100644 day3/d1.c create mode 100644 day3/d10.c create mode 100644 day3/d2.c create mode 100644 day3/d3.c create mode 100644 day3/d4.c create mode 100644 day3/d5.c create mode 100644 day3/d5_2.c create mode 100644 day3/d6.c create mode 100644 day3/d7.c create mode 100644 day3/d8.c create mode 100644 day3/signal_other/test_sigset_t.c create mode 100644 day3/t11.c create mode 100644 day3/t12.c create mode 100644 day3/t13.c create mode 100644 day3/t14.c create mode 100644 day3/t15.c create mode 100644 day3/t16.c create mode 100644 day3/t17.c create mode 100644 day3/t18.c create mode 100644 day3/t19.c create mode 100644 day3/t20.c create mode 100644 day3/t21.c create mode 100644 day3/test_execve.c create mode 100644 day3/test_pause.c create mode 100644 day3/test_sigaction.c diff --git a/README.md b/README.md index 91bc87a..b89d6e1 100644 --- a/README.md +++ b/README.md @@ -297,3 +297,223 @@ pid_t waitpid(pid_t pid, int *status, int options) WIFEXITED(status) 如果子进程是正常终止的,取出的字段值非零 WEXITSTATUS(status) 返回子进程的退出状态,退出状态保存在 status 变量的 8~16 位(低位的第2个字节)。在用此宏前应先用宏 WIFEXITED 判断子进程是否正常退出,正常退出才可以使用此宏。 ``` + +## 三、进程(下),信号 + +### 3.1 ps ja 查看进程状态 + +``` +a 显示终端上的所有进程,包含其他用户的进程 +j 显示父进程号、进程组号、会话号(sid)等信息 +``` + +### 3.2 进程控制 + +``` +#include +_exit(int status_value) 进程的终止及状态值 + +#include +int atexit(void (*function)(void)); 退出清理回调 + + +pid_t vfork(void) 创建新进程但不复制父进程的内存空间,且子进程先执行 + + +进程替换: 不会创建新的进程,只是将进程中执行的程序替换成新的程序 +#include +int execl(const char *pathname,const char *arg0,…,NULL); +int execlp(const char *filename,const char *arg0,…, NULL); +int execle(const char *pathname,const char *arg0,…,NULL, char *const envp[]); +int execv(const char *pathname, char *const argv[]); +int execvp(const char *filename, char *const argv[]); + +int execve(const char *pathname, char *const argv[],char *const envp[]) + + +基于fork+exec执行外部命令或程序 +#include +int system(const char *command); +``` + +### 3.3 进程间通信方式 + +**进程间通信功能:** + +``` +数据传输: 一个进程需要将它的数据发送给另一个进程。 +资源共享: 多个进程之间共享同样的资源。 +通知事件: 一个进程需要向另一个或一组进程发送消息,通知它们发生了某种事件。 +进程控制: 有些进程希望完全控制另一个进程的执行(如 Debug 进程),此时控制进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变。 +``` + +Linux 操作系统支持的主要进程间通信的通信机制: + +``` +UNIX: 信号、无名管道、有名管道、Socket +System V/POSIX: 消息队列、共享内存、信号量 +``` + +### 3.4 信号 + +信号是**软件中断**,它是在软件层次上对中断机制的一种模拟,是一种异步通信的方式。 + +每个信号的名字都以字符 SIG 开头, 命令:`kill -l`查看所有信号 + +信号的基本操作 + +``` +#include +#include +int kill(pid_t pid, int signum); +int raise(int signum); + +#include +unsigned int alarm(unsigned int seconds); +int pause(void); 将调用进程挂起直至捕捉到信号为止 + +#include +void abort(void); 向进程发送一个 SIGABRT(无法阻塞的)信号,默认情况下进程会退出。 + + +``` + +**处理信号** + +> 程序中可用函数 signal()改变信号的处理方式。 + +``` +#include + +typedef void (*sighandler_t)(int); +sighandler_t signal(int signum, sighandler_t handler); +``` + +注册信号处理函数(不可用于 SIGKILL、SIGSTOP 信号),即确定收到信号后处理函数的入口地址。 + +handler 的取值: + +``` +忽略该信号: SIG_IGN +执行系统默认动作: SIG_DFL +自定义信号处理函数: 信号处理函数名 +``` + +返回值: + +``` +成功:返回函数地址,该地址为此信号上一次注册的信号处理函数的地址。 +失败:返回 SIG_ERR +``` + +> 使用 sigaction()处理信号时,必须在第一行声明宏 : +> +> #define \_XOPEN_SOURCE 700 + +``` +#include +int sigaction(int signum, + const struct sigaction *act, + struct sigaction *oldact); +``` + +参数: + +``` +signum:要操作的信号。 +act: 要设置的对信号的新处理方式(传入参数)。 +oldact:原来对信号的处理方式(传出参数)。 + +如果 act 指针非空,则要改变指定信号的处理方式(设置),如果 oldact 指针非空,则系统将此前指定信号的处理方式存入 oldact, 可以为NULL。 +``` + +返回值: 成功:0 失败:-1 + +``` +struct sigaction +{ + void (*sa_handler)(int); //旧的信号处理函数指针 + void (*sa_sigaction)(int, siginfo_t *, void *); //新的信号处理函数指针 + sigset_t sa_mask; //信号阻塞集 + int sa_flags; //信号处理的方式 + void (*sa_restorer)(void); //已弃用 +}; +``` + +1)sa_handler、sa_sigaction:信号处理函数指针,和 signal() 里的函数指针用法一样,应根据情况给 sa_sigaction、sa_handler 两者之一赋值,其取值如下: + +``` +a) SIG_IGN:忽略该信号 +b) SIG_DFL:执行系统默认动作 +c) 处理函数名:自定义信号处理函数 +``` + +2. sa_mask:信号阻塞集,在信号处理函数执行过程中,临时屏蔽指定的信号。 + +3. sa_flags:用于指定信号处理的行为,通常设置为 0,表使用默认属性。它可以是以下值的“按位或”组合: + +``` +SA_RESTART:使被信号打断的系统调用自动重新发起(已经废弃) +SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号。 +SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。 +SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。 +SA_RESETHAND:信号处理之后重新设置为默认的处理方式。 +SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数 +``` + +信号处理函数: + +``` +void(*sa_sigaction)(int signum, siginfo_t *info, void *context); +参数说明: + signum:信号的编号。 + info:记录信号发送进程信息的结构体。 + context:可以赋给指向 ucontext_t 类型的一个对象的指针,以引用在传递信号时被中断的接收进程 +``` + +### 3.5 可重入函数 + +> 可重入函数是指函数可以由多个任务并发使用,而不必担心数据错误。 + +编写可重入函数: + +``` +1、不使用(返回)静态的数据、全局变量(除非用信号量互斥)。 +2、不调用动态内存分配、释放的函数。 +3、不调用任何不可重入的函数(如标准 I/O 函数)。 +``` + +### 3.6 信号集 + +在 PCB 中有两个非常重要的信号集。一个称之为“阻塞信号集”,另一个称之为“未决信号集”。 这两个信号集都是内核使用位图机制来实现的。但操作系统不允许我 们直接对其进行位操作。而需自定义另外一个集合,借助信号集操作函数来对 PCB 中的这两个信号集进行修改。 + +信号集是用来表示多个信号的数据类型。 + +信号集数据类型: `sigset_t` + +信号集相关的操作主要有如下几个函数: + +``` +#include +int sigemptyset(sigset_t *set); +int sigfillset(sigset_t *set); +int sigismember(const sigset_t *set,int signum); +int sigaddset(sigset_t *set, int signum); +int sigdelset(sigset_t *set, int signum); +``` + +### 3.7 信号阻塞集 + +创建一个阻塞集合 + +``` +int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); +``` + +参数:how:信号阻塞集合的修改方法 + +``` +SIG_BLOCK:向信号阻塞集合中添加 set 信号集 +SIG_UNBLOCK:从信号阻塞集合中删除 set 集合 +SIG_SETMASK:将信号阻塞集合设为 set 集合 +``` diff --git a/day3/d1.c b/day3/d1.c new file mode 100644 index 0000000..7beb363 --- /dev/null +++ b/day3/d1.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int main(int argc, char const *argv[]) +{ + // 获取当前程序执行的终端名称 + // 0 是标准输入设备 + printf("终端名: %s, 进程号: %d, 父进程号: %d, 进程组号: %d\n", ttyname(0), getpid(), getppid(), getpgid(0)); + return 0; +} diff --git a/day3/d10.c b/day3/d10.c new file mode 100644 index 0000000..b05d3f8 --- /dev/null +++ b/day3/d10.c @@ -0,0 +1,11 @@ +#include +#include + +int main(int argc, char const *argv[]) +{ + // int ret = system("ls -l"); + // int ret = system("./d7"); + int ret = system(argv[1]); + printf("ret = %d\n", ret); + return 0; +} \ No newline at end of file diff --git a/day3/d2.c b/day3/d2.c new file mode 100644 index 0000000..3e9e7f9 --- /dev/null +++ b/day3/d2.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char const *argv[]) +{ + pid_t pid = fork(); + if (pid == 0) // 子进程 + { + printf("子进程 %d 立即结束\n", getpid()); + sleep(2); // 休眠 2 秒 + // return 10; + _exit(12); + } + else if (pid > 0) // 父进程 + { + printf("父进程 %d 运行中\n", getpid()); + // 回收资源 (wait/waitpid) ,不然子进程资源依然占用 + int status; + // int pid2 = wait(&status); + waitpid(pid, &status, 0); + // 右移 8 位为状态值 + // printf("%d 子进程返回的状态值: %d\n", pid, (status & 0xff00) >> 8); + if (WIFEXITED(status)) + { + printf("%d 子进程返回的状态值: %d\n", pid, WEXITSTATUS(status)); + } + } + return 0; +} diff --git a/day3/d3.c b/day3/d3.c new file mode 100644 index 0000000..7a46b84 --- /dev/null +++ b/day3/d3.c @@ -0,0 +1,40 @@ +// 请分析如下程序,如何实现创建2个子进程, 第一个子进程输出ABC, 第二子进程输出 DEF。 +// 做法二 +#include +#include +#include +#include +#include // atexit + +void clearAll1() +{ + printf("%d 清退资源1...\n", getpid()); +} + +void clearAll2() +{ + printf("%d 清退资源2...\n", getpid()); +} + +int main(int argc, char *argv[]) +{ + atexit(clearAll1); // 清退,退出前执行 + atexit(clearAll2); + int pid = fork(); + if (pid == 0) + { + sleep(5); + printf("%d 子进程结束\n", getpid()); + // atexit(clearAll); // 清退,退出前执行,子进程无法清退 + _exit(1); + } + else if (pid > 0) + { + // atexit(clearAll); // 清退,退出前执行 + + wait(NULL); // 等待子进程 + printf("主进程 %d 结束\n", getpid()); + } + + return 0; +} diff --git a/day3/d4.c b/day3/d4.c new file mode 100644 index 0000000..839a720 --- /dev/null +++ b/day3/d4.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include // atexit +#include + +int main(int argc, char const *argv[]) +{ + int num = 10; + // vfork 子进程和父进程会共享内存 + pid_t pid = vfork(); + if (pid == 0) + { + // 子进程 + num += 10; + printf("%d 子进程 num=%d\n", getpid(), num); + _exit(0); // 回收资源退出 + } + + else if (pid > 0) + { + // 父进程 + printf("%d 父进程 num=%d\n", getpid(), num); + } + + return 0; +} diff --git a/day3/d5.c b/day3/d5.c new file mode 100644 index 0000000..e28f2de --- /dev/null +++ b/day3/d5.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include // atexit +#include + +int main(int argc, char const *argv[]) +{ + // vfork 子进程和父进程会共享内存 + pid_t pid = vfork(); + if (pid == 0) + { + // 子进程 + for (int i = 0; i < 5; i++) + { + printf("%d vfork的子进程 i=%d\n", getpid(), i); + + sleep(1); + } + _exit(0); // 回收资源退出; vfork创建的子进程结束后,才会执行父进程 + } + + else if (pid > 0) + { + // 父进程 + while (1) + { + printf("%d 父进程 \n", getpid()); + sleep(1); + } + } + + return 0; +} diff --git a/day3/d5_2.c b/day3/d5_2.c new file mode 100644 index 0000000..4b14719 --- /dev/null +++ b/day3/d5_2.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include // atexit +#include + +int main(int argc, char const *argv[]) +{ + pid_t pid = vfork(); + if (pid == 0) + { + for (int i = 0; i < 3; i++) + { + // vfork 子进程和父进程会共享内存 + pid = vfork(); + if (pid == 0) + { + // 子进程 + for (int i = 0; i < 5; i++) + { + printf("%d vfork的子进程 i=%d\n", getpid(), i); + + sleep(1); + } + _exit(0); // 回收资源退出; vfork创建的子进程结束后,才会执行父进程 + } + } + } + + else if (pid > 0) + { + // 父进程 + while (1) + { + printf("%d 父进程 \n", getpid()); + sleep(1); + } + } + + return 0; +} diff --git a/day3/d6.c b/day3/d6.c new file mode 100644 index 0000000..4b391dd --- /dev/null +++ b/day3/d6.c @@ -0,0 +1,21 @@ +#include +#include + +int main() +{ + printf("当前进程号: %d\n", getpid()); + + // 执行 ls 命令 + // int ret = execl("/bin/ls", "ls", "-l", "../", NULL); + int ret = execlp("ls", "ls", "-l", "./", NULL); + // 执行 d5 程序 + // int ret = execl("./d5", "d5", NULL); + // int ret = execlp("./d5", NULL); + + if (ret == -1) + { + perror("execl"); // 只有错误才会返回 + } + + return 0; +} \ No newline at end of file diff --git a/day3/d7.c b/day3/d7.c new file mode 100644 index 0000000..21c3fcf --- /dev/null +++ b/day3/d7.c @@ -0,0 +1,15 @@ +#include +#include // getenv 获取环境变量 + +int main() +{ + // 读取 d8 中的环境变量值 + // 读取环境变量 PYTHON_HOME + char *JAVA_HOME = getenv("JAVA_HOME"); + printf("JAVA_HOME: %s\n", JAVA_HOME); + + char *PYTHON_HOME = getenv("PYTHON_HOME"); + printf("PYTHON_HOME: %s\n", PYTHON_HOME); + + return 0; +} \ No newline at end of file diff --git a/day3/d8.c b/day3/d8.c new file mode 100644 index 0000000..c4c786f --- /dev/null +++ b/day3/d8.c @@ -0,0 +1,15 @@ +#include +#include + +int main() +{ + // 环境变量动态设置,用于 d7 的读取 + char *env[] = {"JAVA_HOME=/opt/java", "PYTHON_HOME=/opt/python", NULL}; + int ret = execle("./d7", "d7", NULL, env); + if (ret == -1) + { + perror("./d7"); + } + + return 0; +} \ No newline at end of file diff --git a/day3/signal_other/test_sigset_t.c b/day3/signal_other/test_sigset_t.c new file mode 100644 index 0000000..b39a346 --- /dev/null +++ b/day3/signal_other/test_sigset_t.c @@ -0,0 +1,48 @@ +// 信号集问题 +#define _XOPEN_SOURCE 700 +#include +#include +// #include + +// 定义一个宏,用于检查信号编号是否有效 +#define _NSIG 64 +#define NSIG _NSIG +#define SIGBAD(signo) ((signo) <= 0 || (signo) >= NSIG) + +// 向信号集中添加一个信号 +int sigaddset(sigset_t *set, int signo) +{ + // 检查信号编号是否有效 + if (SIGBAD(signo)) + { + errno = EINVAL; // 设置错误码为无效参数 + return (-1); // 返回错误 + } + *set |= 1 << (signo - 1); /* 将对应位设置为1 */ + return (0); // 返回成功 +} + +// 从信号集中删除一个信号 +int sigdelset(sigset_t *set, int signo) +{ + // 检查信号编号是否有效 + if (SIGBAD(signo)) + { + errno = EINVAL; // 设置错误码为无效参数 + return (-1); // 返回错误 + } + *set &= ~(1 << (signo - 1)); /* 将对应位设置为0 */ + return (0); // 返回成功 +} + +// 检查一个信号是否在信号集中 +int sigismember(const sigset_t *set, int signo) +{ + // 检查信号编号是否有效 + if (SIGBAD(signo)) + { + errno = EINVAL; // 设置错误码为无效参数 + return (-1); // 返回错误 + } + return ((*set & (1 << (signo - 1))) != 0); // 返回信号是否在信号集中 +} diff --git a/day3/t11.c b/day3/t11.c new file mode 100644 index 0000000..44ebf51 --- /dev/null +++ b/day3/t11.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include +#include + +// kill 案例:组合搭配 t12 使用 +int main() +{ + fork(); + printf("%d 组ID(%d) 努力工作中...\n", getpid(), getpgid(0)); + while (1) + ; + return 0; +} \ No newline at end of file diff --git a/day3/t12.c b/day3/t12.c new file mode 100644 index 0000000..ab5ea89 --- /dev/null +++ b/day3/t12.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + +// kill 案例 +int main() +{ + // -3493 干掉 3493 进程组的所有进程 + int s = kill(-3493, SIGKILL); + if (s == -1) + { + perror("kill"); + return 1; + } + printf("kill result: %d\n", s); + return 0; +} \ No newline at end of file diff --git a/day3/t13.c b/day3/t13.c new file mode 100644 index 0000000..27d3075 --- /dev/null +++ b/day3/t13.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include +#include + +// kill 案例 +int main() +{ + int pid = fork(); + if (pid == 0) + { + while (1) + { + printf("%d 玩一会游戏\n", getpid()); + sleep(2); + } + } + + else if (pid > 0) + { + printf("%d 子进程正在学习\n", pid); + sleep(5); + kill(pid, SIGKILL); + printf("主进程 %d 干掉了子进程 %d \n", getpid(), pid); + } + return 0; +} \ No newline at end of file diff --git a/day3/t14.c b/day3/t14.c new file mode 100644 index 0000000..8d8eef9 --- /dev/null +++ b/day3/t14.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include + +int main() +{ + pid_t pid; + pid = fork(); + if (pid == 0) + { + // 子进程 + printf("10 秒后子进程退出\n"); + int s = alarm(10); // 第一次调用, s 返回 0 + printf("alarm s is %d\n", s); + sleep(3); + s = alarm(10); + printf("alarm s is %d\n", s); + + while (1) + ; + } + return 0; +} \ No newline at end of file diff --git a/day3/t15.c b/day3/t15.c new file mode 100644 index 0000000..afa3d23 --- /dev/null +++ b/day3/t15.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include + +// 定时器的使用 alarm 函数的使用 +void alarm_handle(int sig) +{ + printf("接收到了 SIGALRM(%d) 信号\n", sig); +} + +int main() +{ + struct itimerval new_value; + + // 首次触发信号的时间 + new_value.it_value.tv_sec = 5; //5秒后发送信号 + new_value.it_value.tv_usec = 0; //微秒 + + // 之后每次触发信号的时间 + new_value.it_interval.tv_sec = 1; //每隔1秒发送信号 + new_value.it_interval.tv_usec = 0; + + // 注册信号处理函数 + signal(SIGALRM, alarm_handle); //注册信号处理函数 + // 信号处理函数的注册方式 + setitimer(ITIMER_REAL, &new_value, NULL); //设置定时器 + + while (1) + ; //程序进入死循环,等待信号 + + return 0; +} \ No newline at end of file diff --git a/day3/t16.c b/day3/t16.c new file mode 100644 index 0000000..ceae367 --- /dev/null +++ b/day3/t16.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include // sleep + +// 信号处理函数 raise 的使用 +int main() +{ + printf("2 秒之后 kill 本进程\n"); + sleep(2); + // 可以发出中断的信号有: SIGINT, SIGQUIT, SIGTERM, SIGKILL + raise(SIGALRM); // 退出信号 + sleep(10); + printf("本进程不会进行到这里 \n"); + return 0; +} \ No newline at end of file diff --git a/day3/t17.c b/day3/t17.c new file mode 100644 index 0000000..9a995da --- /dev/null +++ b/day3/t17.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include // sleep +#include + +// 信号处理函数 SIGINT 信号处理函数 +int main() +{ + printf("2 秒之后中断本进程\n"); + sleep(2); + printf("不会执行到这里\n"); + raise(SIGINT); // 向本进程发送 SIGINT 信号 + abort(); //结束进程之前, 刷新缓冲区,关闭所有的文件描述符(0/1/2) + return 0; +} \ No newline at end of file diff --git a/day3/t18.c b/day3/t18.c new file mode 100644 index 0000000..a1c5d73 --- /dev/null +++ b/day3/t18.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include // sleep + +int main() +{ + printf("2秒后挂起, 等待信号 SIGINT\n"); + sleep(2); + if (f = pause() == -1) + { + printf("pause error\n"); + } + else + { + printf("pause return\n"); + } +} \ No newline at end of file diff --git a/day3/t19.c b/day3/t19.c new file mode 100644 index 0000000..a0f3cca --- /dev/null +++ b/day3/t19.c @@ -0,0 +1,30 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include + +void handler(int sig) +{ + printf("sig is %d, handler ...\n", sig); + // exit(0); +} + +int main() +{ + struct sigaction sa; + sa.sa_handler = handler; + + sigfillset(&sa.sa_mask); + + // sa.sa_flags = 0; + // 信号只能被处理一次,下次恢复默认行为 + // sa.sa_flags |= SA_RESETHAND; // 重置默认的信号处理行为 + + sigaction(SIGINT, &sa, NULL); + while (1) + ; + return 0; +} \ No newline at end of file diff --git a/day3/t20.c b/day3/t20.c new file mode 100644 index 0000000..3795119 --- /dev/null +++ b/day3/t20.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include + +void show(int n) +{ + for (int i = 0; i < n; i++) + { + // printf("%d 进程 -> %d\n", getpid(), i); + char buf[32]; + sprintf(buf, "%d 进程 -> %d\n", getpid(), i); + /* + #define STDIN_FILENO 0 // Standard input. + #define STDOUT_FILENO 1 // Standard output. + #define STDERR_FILENO 2 // Standard error output. + */ + write(STDOUT_FILENO, buf, strlen(buf)); + sleep(1); + } +} + +int main() +{ + for (int i = 0; i < 5; i++) + { + int pid = fork(); + if (pid == 0) + { + show(i + 1); + _exit(0); + } + } + while (1) + { + int status; + int pid = waitpid(0, &status, WUNTRACED); + if (pid == -1) + { + break; + } + printf("%d 子进程结束\n", pid); + } + + return 0; +} \ No newline at end of file diff --git a/day3/t21.c b/day3/t21.c new file mode 100644 index 0000000..0bb03fd --- /dev/null +++ b/day3/t21.c @@ -0,0 +1,47 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include + +int main(int argc, char const *argv[]) +{ + // 定义一个信号集 + sigset_t set; + + // 所有信号填充到信号集 + // sigfillset(&set); + // printf("SIGINT in set ? %d\n", sigismember(&set, SIGINT)); + + // 清空set集 + sigemptyset(&set); + printf("SIGINT in set ? %d\n", sigismember(&set, SIGINT)); + + // 将SIGINT添加到set集合中 (Ctrl+C触发中断信号,终止进程) + sigaddset(&set, SIGINT); + // 将SIGTSTP添加到set集和中 (终端停止信号) + sigaddset(&set, SIGTSTP); + + if (sigismember(&set, SIGINT)) + { + printf("SIGINT是在set集合中\n"); + } + else + { + printf("SIGINT不在set集合中\n"); + } + + // 将SIGINT从集合中删除 + sigdelset(&set, SIGINT); + if (sigismember(&set, SIGINT)) + { + printf("SIGINT是在set集合中\n"); + } + else + { + printf("SIGINT不在set集合中\n"); + } + + return 0; +} \ No newline at end of file diff --git a/day3/test_execve.c b/day3/test_execve.c new file mode 100644 index 0000000..c5b205f --- /dev/null +++ b/day3/test_execve.c @@ -0,0 +1,11 @@ +#include +#include + +int main() +{ + char *const argv[] = {"ls", "-l", NULL}; + char *const envp[] = {"PATH=/usr/local/bin", "TERM=vt100", NULL}; + execve("/bin/ls", argv, envp); + + return 0; +} diff --git a/day3/test_pause.c b/day3/test_pause.c new file mode 100644 index 0000000..b8e79a7 --- /dev/null +++ b/day3/test_pause.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include + +int main() +{ + pid_t pid; + pid = fork(); + if (pid < 0) + { + perror("fork"); + exit(1); + } + + else if (pid > 0) // 父进程的代码 + { + printf("这是父进程\n"); + // 使用 pause 阻塞等待捕捉信号 + pause(); + } + else // 子进程的代码区 + { + printf("这是子进程\n"); + sleep(3); + kill(getppid(), SIGINT); + } + + return 0; +} \ No newline at end of file diff --git a/day3/test_sigaction.c b/day3/test_sigaction.c new file mode 100644 index 0000000..8488e88 --- /dev/null +++ b/day3/test_sigaction.c @@ -0,0 +1,38 @@ +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include + +void sigint_handler(int signum) +{ + printf("捕捉到 SIGINT 信号,程序即将退出。\n"); + exit(0); +} + +int main() +{ + struct sigaction sa; + sa.sa_handler = sigint_handler; + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGINT); + sigfillset(&sa.sa_mask); + // sa.sa_flags = 0; + sa.sa_flags |= SA_RESETHAND; // 重置默认的信号处理行为 + + if (sigaction(SIGINT, &sa, NULL) == -1) + { + perror("sigaction"); + exit(1); + } + + printf("程序运行中,按 Ctrl+C 发送 SIGINT 信号退出。\n"); + + while (1) + { + // 程序持续执行 + sleep(1); + } + + return 0; +}