目录
前言:
不同的系统有不同的系统调用,相比于WindowsAPI中进线程的管理,我更喜欢Linux的进程管理(我才不会告诉你因为WindowsAPI代码对我来说太过繁重)。所以让我们来一起学习Linux进线程管理吧,首先对于Linux我们肯定是要了解进程管理命令的,然后才是我们的编程级别的进程创建与管理。
一、进程管理命令
1、在指定时间执行程序
命令格式:at time [day] [file]
说明:用户使用at命令在指定时刻执行指定的命令序列。
例如:10分钟后执行who命令(显示当前登录系统的用户)
$ at now +10min
at>who
at><EOT>(使用ctrl+D即可完成任务设定,会出现这个标志)
2、进程的挂起与恢复命令
命令格式:bg/fg
说明:bg命令用来迫使被挂起的进程在后台运行。例如,当用户已经在前台启动了一个命令,但是它执行时间较长,而我们这个时候需要使用shell,那么我们可以ctrl+z把它挂起,然后bg命令放到后台执行,使用fg可以激活某个被挂起的进程并使它在前台运行。
例如:
$ ./hello
Ctrl +Z
$ bg
或者唤醒
$ fg
3、查看当前在线上的用户情况
命令格式:who
说明:该命令主要用于查看线上的用户情况,系统管理员可以通过该命令监视每个登录用户的情况。
4、显示当前登录的用户正在执行的命令
命令格式:w
说明:w命令与who命令相比功能更加的强大,显示项目按照顺序排列:当前时间,系统启动到现在的时间,登录用户的数目,系统在最近1s、5s和15s的平均负载,最后是每个用户的各项数据,各项数据显示如下:登录账号、终端名称、远程主机名、登录时间、空闲时间、JCPU(和该终端连接的所有进程所占用的时间)、PCPU(当前进程所占用的时间)、当前正在运行进程的命令行。
例如:
5、进程查看命令
命令格式:ps 【选项】
说明:改命令可以确定有哪些进程正在运行以及运行的状态、进程是否结束、哪些进程占用了过多的资源等。ps命令最常用的功能还是监控后台进程的工作情况。
选项含义:
-e 显示所有进程
-f 全格式
-h 不显示标题
-l 长格式
-w 宽输出
-a 显示终端上的所有进程,包括其他用户的进程
-r 只显示正在运行的进程
-x 显示没有空格终端的进程
例如:
以长格式查看属于自己的进程的详细信息
$ ps -l
6、指向的进程发送信号
命令格式:kill [-signal]进程号
说明:kill命令可以终止后台进程。kill命令时通过向进程发送指定的信号来结束进程的。如果没有发送指定信号,那么默认值为SIGTERM信号。SIGTERM信号将终止所有不能捕获该信号的进程。至于那些可以捕获该信号的进程可能就需要使用kill-9信号了,该信号是不能被捕获的。
选项含义:
-signal 发送的信号类型,默认值为15,即SIGTERM信号,取值范围是1~30
例如,删除进程号(PID)为1330的进程:
$ kill 1330
若普通的无法删除,那么用:
$ kill -15 1330
如果连-15都无法删除,那么用:
$ kill -9 1330
二、进程管理(编程级别的)
看完那么多炫酷的命令操作,在开始编程之前,让我们看看相关的函数。
1、fork()函数
fork()函数用于创建一个新进程(子进程)。其调用格式为:int fork();
其返回值:
等于 0,表示当前进程时子进程,从子进程返回的ID值
大于 0, 表示当前进程时父进程,从父进程返回的子进程的进程ID值
等于-1,那么创建失败
2、wait()函数
wait()函数用来控制父进程与子进程的同步。在父进程中调用wait()函数,则父进程被阻塞,进入等待队列,等待子进程结束。当子进程结束时,会产生一个终止状态字,系统会向父进程发出SIGCHLD信号。接到信号后,父进程提取子进程的终止状态字,从wait()函数返回,继续执行原程序。调用格式为:
#include<sys/type.h>
#include<sys/wait.h>
(pid_t) wait(int *statloc);
返回值:
大于0,为子进程的ID值
等于0,为其它
等于-1,表示调用失败
3、exit()函数
exit()函数是进程结束最常用的函数,在main()函数中调用return,最终也是调用exit()函数(啊,C语言return 0白学了doge)。这些都是进程的正常终止。
调用格式为:
#include<stdio.h>
void exit(int status);
4、kill()函数
kill()函数用于删除执行中的程序或者任务,调用格式为kill(int PID,int IID);
其中PID是要被杀死的进程号,IID为向将要被杀死的进程发送的中断号
5、signal()函数
signal()函数是允许调用进程控制软中断信号的处理。
格式为:
#include<signal.h>
int sig;
void(*func)();
signal(sig,function);
6、pipe()函数
pipe()函数用于创建一个管道,其调用格式为:
#include<unistd.h>
pipe(int fp[2]);
那么让我们开始编程实现软中断通信吧,????你是不是有很多问好,什么是软中断,哈哈,其实就是模拟中断啦,让我们看看概念。
中断(interrupt),是指计算机在执行期间,系统内发生任何非寻常的或非预期的急需处理时间,使得CPU不得不暂停当前正在执行的程序而转去执行相应的事件处理程序,待处理完毕后再返回原来被中断处继续执行的过程。中断的发生一般而言是异步的,换句话说即使在无法预测的情况发生的(比如系统掉电)。所以计算机的软硬件对于中断的相应反应完全是被动的。
软中断是对硬中断的一种模拟,发送软中断就是向接受程序的proc结构中的相应项发送一个特定意义的信号。软中断必须等到接收进程执行时才能生效。
所以,我们只是模拟进程中创建、阻塞等情况呀,一起来编程吧!
编译运行环境:centOS
#include<stdio.h>//exit()函数头文件
#include<signal.h>//signal()函数头文件
#include<unistd.h>//wait函数头文件
#include<sys/types.h>
int wait_flag;
void stop();//C语言函数原型声明,当然直接定义也可以,这里在末尾定义函数体
main() {
int pid1,pid2;//定义两个进程号变量
signal(3,stop);//sig==3为SIGQUIT退出
while((pid1 = fork()) == -1);//若创建子进程1不成功,则空循环
if(pid1>0) {
while((pid2=fork())==-1);//若创建子进程2不成功,则空循环
if(pid1>0) {
wait_flag = 1;
sleep(5);//父进程等待5s
kill(pid1,16);//杀死子进程1
kill(pid2,17);//杀死子进程2
wait(0);//等待第一个子进程结束的信号
wait(0);//等待第二个子进程结束的信号
printf("\nParent process is killed!!\n");
exit(0);//父进程结束
}
else {
wait_flag = 1;
signal(17,stop);//等待子进程2被杀死的中断号17
printf("\nChild process 2 is killed by parent!!\n");
exit(0);
}
}
else{
wait_flag = 1;
signal(16,stop);//等待子进程1被杀死的中断号16
printf("\nChild process 1 is killed by parent!!\n");
exit(0);
}
}
void stop(){
wait_flag = 0;
}
输出可能是:
Child process 1 is killed by parent!!
Child process 2 is killed by parent!!
Parent process is killed!!
或者:
Child process 2 is killed by parent!!
Child process 1 is killed by parent!!
Parent process is killed!!
这个是因为从进程调度的角度来看,子进程被创建后处于就绪状态。此时,父进程和子进程作为两个独立的进程,共享一个代码段,分别参加调度、执行,直至进程结束。但是谁先谁后,和系统的调度策略和系统当前的资源状态有关,是不确定的。因为谁先从fork()函数中返回继续执行后面的语句也是不确定的。
上面的wait、exit是很好理解的,但是signal可能就比较难理解。调用函数signal()都放在一段程序的前部,而不是在其他接收信号处。这是因为signal()执行只是起到为进程指定信号量16和17的作用,以及分配相应的与stop()过程链接的指针,从而signal()函数必须在程序的前部执行。其中sig的取值想要仔细了解可以找度娘查看。
总结:
这篇博客简单的展示了Linux进程控制编程,要更深一步的了解,需要编写大量的实例,并去理解它们,关注我,一起学习呀,如有误,请指出,谢谢!