进程调度

两个信号

SIGTSTP

停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号

SIGINT

程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。

系统调用

getpid()系统调用

getpid()系统调用语法:

1
2
3
4
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);

getpid返回当前进程的进程号,getppid返回当前进程父进程的进程号

进程控制有关的系统调用

可以通过信号向一个进程发送消息以控制进程的行为。信号是由中断或异常事件引发的,如:键盘中断、定时器中断、非法内存引用等。信号的名字都以SIG 开头,例如SIGTERM、SIGHUP。可以使用kill -l 命令查看系统当前的信号集合。

信号可在任何时间发生,接收信号的进程可以对接收到的信号采取3种处理措施之一:

  • 忽略这个信号

  • 执行系统默认的处理

  • 捕捉这个信号做自定义的处理

信号从产生到被处理所经过的过程:

产生(generate)->挂起(pending)->派送(deliver)->部署(disposition)或忽略(igore)

一个信号集合是一个C语言的sigset_t数据类型的对象,sigset_t数据类型定义在<signal.h>中。被一个进程忽略的所有信号的集合称为一个信号掩码(mask)。

从程序中向一个进程发送信号有两种方法:调用 shellkill命令,调用kill系统调用函数。kill能够发送除杀死一个进程(SIGKILLSIGTERMSIGQUIT)之外的其他信号,例如键盘中断(Ctrl+C)信号SIGINT,进程暂停(Ctrl+Z)信号SIGTSTP等等。

调用pause() 函数会令调用进程的执行挂起直到一个任意信号到来后再继续运行。

调用sleep() 函数会令调用进程的执行挂起睡眠指定的秒数或一个它可以响应的信号到来后继续执行。

每个进程都能使用signal 函数定义自己的信号处理函数,捕捉并自行处理接收的除SIGSTOPSIGKILL之外的信号。以下是有关的系统调用的语法说明。

kill系统调用语法:

1
2
3
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

pid: 接收信号的进程号

signal: 要发送的信号

kill发送成功返回接收者的进程号,失败返回-1。

pause 系统调用语法:

1
2
#include <unistd.h>
int pause(void);

pause 挂起调用它的进程直到有任何信号到达。调用进程不自定义处理方法,则进行信号的默认处理。只有进程自定义了信号处理方法捕获并处理了一个信号后,pause 才会返回调进程。pause 总是返回-1,并设置系统变量errnoEINTR

sleep系统调用语法:

1
2
#include <unistd.h>
unsigned int sleep(unsigned int seconds);

seconds 指定进程睡眠的秒数,如果指定的秒数到,sleep返回0。

signal系统调用语法:

1
2
3
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

signum: 要捕捉的信号

handler: 进程中自定义的信号处理函数名

signal 调用成功会返回信号处理函数的返回值,不成功返回-1,并设置系统变量errnoSIG_ERR

另外

c语言请记得用while(1)代替while(true)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
#include <unistd.h>
typedef void (*sighandler_t)(int);

void sigint(){
int pri = 0;
pri = getpriority(PRIO_PROCESS, 0); // 获取当前进程的优先级
if (pri >= -20 && pri < 19)
pri += 1;
printf("将进程%d优先级+1\n", getpid());
setpriority(PRIO_PROCESS, getpid(), pri);
}

void sigtstp(){
int pri = 0;
pri = getpriority(PRIO_PROCESS, 0); // 获取当前进程的优先级
if (pri > -20 && pri <= 19)
pri -= 1;
printf("将进程%d优先级-1\n", getpid());
setpriority(PRIO_PROCESS, getpid(), pri);
}

int main(int argc, char *argv[]){
int pidParent, pidChild;

pidParent = getpid();
pidChild = fork();

if (pidChild < 0){
printf("子进程创建失败!\n");
exit(EXIT_FAILURE);
}else if (pidChild > 0){
signal(SIGINT, (sighandler_t)sigint);
signal(SIGTSTP, (sighandler_t)sigtstp);
while(1){
printf("父进程进程号为%d,策略为%d,优先级为%d\n", pidParent, sched_getscheduler(pidParent), getpriority(PRIO_PROCESS, 0));
kill(pidChild, SIGCONT);
sleep(4);
}
}else{
signal(SIGINT, (sighandler_t)sigint);
signal(SIGTSTP, (sighandler_t)sigtstp);
while(1){
printf("子进程进程号为%d,策略为%d,优先级为%d\n", getpid(), sched_getscheduler(getpid()), getpriority(PRIO_PROCESS, 0));
kill(pidParent, SIGCONT);
sleep(4);
}
}

return EXIT_SUCCESS;
}