进程(下),信号
This commit is contained in:
parent
560a595823
commit
85e2fc451e
220
README.md
220
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 <unistd.h>
|
||||
_exit(int status_value) 进程的终止及状态值
|
||||
|
||||
#include <stdlib.h>
|
||||
int atexit(void (*function)(void)); 退出清理回调
|
||||
|
||||
|
||||
pid_t vfork(void) 创建新进程但不复制父进程的内存空间,且子进程先执行
|
||||
|
||||
|
||||
进程替换: 不会创建新的进程,只是将进程中执行的程序替换成新的程序
|
||||
#include <unistd.h>
|
||||
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 <stdlib.h>
|
||||
int system(const char *command);
|
||||
```
|
||||
|
||||
### 3.3 进程间通信方式
|
||||
|
||||
**进程间通信功能:**
|
||||
|
||||
```
|
||||
数据传输: 一个进程需要将它的数据发送给另一个进程。
|
||||
资源共享: 多个进程之间共享同样的资源。
|
||||
通知事件: 一个进程需要向另一个或一组进程发送消息,通知它们发生了某种事件。
|
||||
进程控制: 有些进程希望完全控制另一个进程的执行(如 Debug 进程),此时控制进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变。
|
||||
```
|
||||
|
||||
Linux 操作系统支持的主要进程间通信的通信机制:
|
||||
|
||||
```
|
||||
UNIX: 信号、无名管道、有名管道、Socket
|
||||
System V/POSIX: 消息队列、共享内存、信号量
|
||||
```
|
||||
|
||||
### 3.4 信号
|
||||
|
||||
信号是**软件中断**,它是在软件层次上对中断机制的一种模拟,是一种异步通信的方式。
|
||||
|
||||
每个信号的名字都以字符 SIG 开头, 命令:`kill -l`查看所有信号
|
||||
|
||||
信号的基本操作
|
||||
|
||||
```
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
int kill(pid_t pid, int signum);
|
||||
int raise(int signum);
|
||||
|
||||
#include <unistd.h>
|
||||
unsigned int alarm(unsigned int seconds);
|
||||
int pause(void); 将调用进程挂起直至捕捉到信号为止
|
||||
|
||||
#include <stdlib.h>
|
||||
void abort(void); 向进程发送一个 SIGABRT(无法阻塞的)信号,默认情况下进程会退出。
|
||||
|
||||
|
||||
```
|
||||
|
||||
**处理信号**
|
||||
|
||||
> 程序中可用函数 signal()改变信号的处理方式。
|
||||
|
||||
```
|
||||
#include <signal.h>
|
||||
|
||||
typedef void (*sighandler_t)(int);
|
||||
sighandler_t signal(int signum, sighandler_t handler);
|
||||
```
|
||||
|
||||
注册信号处理函数(<font color=red>不可用于 SIGKILL、SIGSTOP 信号</font>),即确定收到信号后处理函数的入口地址。
|
||||
|
||||
handler 的取值:
|
||||
|
||||
```
|
||||
忽略该信号: SIG_IGN
|
||||
执行系统默认动作: SIG_DFL
|
||||
自定义信号处理函数: 信号处理函数名
|
||||
```
|
||||
|
||||
返回值:
|
||||
|
||||
```
|
||||
成功:返回函数地址,该地址为此信号上一次注册的信号处理函数的地址。
|
||||
失败:返回 SIG_ERR
|
||||
```
|
||||
|
||||
> 使用 sigaction()处理信号时,必须在第一行声明宏 :
|
||||
>
|
||||
> #define \_XOPEN_SOURCE 700
|
||||
|
||||
```
|
||||
#include <signal.h>
|
||||
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 中的这两个信号集进行修改。
|
||||
|
||||
<font color=blue><b>信号集是用来表示多个信号的数据类型。</b></font>
|
||||
|
||||
信号集数据类型: `sigset_t`
|
||||
|
||||
信号集相关的操作主要有如下几个函数:
|
||||
|
||||
```
|
||||
#include <signal.h>
|
||||
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 集合
|
||||
```
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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); // 返回信号是否在信号集中
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue