进程(下),信号

This commit is contained in:
2023-08-17 09:20:18 +08:00
parent 560a595823
commit 85e2fc451e
26 changed files with 896 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char const *argv[])
{
// 获取当前程序执行的终端名称
// 0 是标准输入设备
printf("终端名: %s, 进程号: %d, 父进程号: %d, 进程组号: %d\n", ttyname(0), getpid(), getppid(), getpgid(0));
return 0;
}
+11
View File
@@ -0,0 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
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;
}
+33
View File
@@ -0,0 +1,33 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
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;
}
+40
View File
@@ -0,0 +1,40 @@
// 请分析如下程序,如何实现创建2个子进程, 第一个子进程输出ABC, 第二子进程输出 DEF。
// 做法二
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h> // 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;
}
+28
View File
@@ -0,0 +1,28 @@
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h> // atexit
#include <fcntl.h>
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;
}
+35
View File
@@ -0,0 +1,35 @@
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h> // atexit
#include <fcntl.h>
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;
}
+42
View File
@@ -0,0 +1,42 @@
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h> // atexit
#include <fcntl.h>
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;
}
+21
View File
@@ -0,0 +1,21 @@
#include <stdio.h>
#include <unistd.h>
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;
}
+15
View File
@@ -0,0 +1,15 @@
#include <stdio.h>
#include <stdlib.h> // 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;
}
+15
View File
@@ -0,0 +1,15 @@
#include <stdio.h>
#include <unistd.h>
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;
}
+48
View File
@@ -0,0 +1,48 @@
// 信号集问题
#define _XOPEN_SOURCE 700
#include <signal.h>
#include <errno.h>
// #include <sigset.h>
// 定义一个宏,用于检查信号编号是否有效
#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); // 返回信号是否在信号集中
}
+15
View File
@@ -0,0 +1,15 @@
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
// kill 案例:组合搭配 t12 使用
int main()
{
fork();
printf("%d 组ID(%d) 努力工作中...\n", getpid(), getpgid(0));
while (1)
;
return 0;
}
+19
View File
@@ -0,0 +1,19 @@
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
// 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;
}
+28
View File
@@ -0,0 +1,28 @@
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
// 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;
}
+25
View File
@@ -0,0 +1,25 @@
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
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;
}
+35
View File
@@ -0,0 +1,35 @@
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/time.h>
// 定时器的使用 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;
}
+16
View File
@@ -0,0 +1,16 @@
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h> // sleep
// 信号处理函数 raise 的使用
int main()
{
printf("2 秒之后 kill 本进程\n");
sleep(2);
// 可以发出中断的信号有: SIGINT, SIGQUIT, SIGTERM, SIGKILL
raise(SIGALRM); // 退出信号
sleep(10);
printf("本进程不会进行到这里 \n");
return 0;
}
+16
View File
@@ -0,0 +1,16 @@
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h> // sleep
#include <stdlib.h>
// 信号处理函数 SIGINT 信号处理函数
int main()
{
printf("2 秒之后中断本进程\n");
sleep(2);
printf("不会执行到这里\n");
raise(SIGINT); // 向本进程发送 SIGINT 信号
abort(); //结束进程之前, 刷新缓冲区,关闭所有的文件描述符(0/1/2)
return 0;
}
+18
View File
@@ -0,0 +1,18 @@
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h> // sleep
int main()
{
printf("2秒后挂起, 等待信号 SIGINT\n");
sleep(2);
if (f = pause() == -1)
{
printf("pause error\n");
}
else
{
printf("pause return\n");
}
}
+30
View File
@@ -0,0 +1,30 @@
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
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;
}
+48
View File
@@ -0,0 +1,48 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <string.h>
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;
}
+47
View File
@@ -0,0 +1,47 @@
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
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;
}
+11
View File
@@ -0,0 +1,11 @@
#include <stdio.h>
#include <unistd.h>
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;
}
+31
View File
@@ -0,0 +1,31 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
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;
}
+38
View File
@@ -0,0 +1,38 @@
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
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;
}