Linux进程简介
进程4要素
要有一段程序供该进程运行
进程专用的系统堆栈空间
进程控制块(PCB),具体实现是task_struct结构
有独立的存储空间
交互进程:由一个Shell启动的进程,既可以在前台运行,又可以在后台运行
批处理进程:这种进程和终端没有联系,是一个进程序列
监控进程(守护进程):Linux启动时启动的进程,并在后台运行
进程控制块
进程标识符:每个进程的唯一标识符,可以是字符串,也可以是数字。
进程当前状态:为方便管理,相同状态的进程会组成一个队列,如就绪进程队列。
进程相应的程序和数据地址:以便把PCB与其程序和数据联系起来。
进程资源清单:列出所有除CPU外的资源记录,如拥有的I/O设备,打开的文件列表等。
进程优先级:反映进程的紧迫程度,通常由用户指定和系统设置。
CPU现场保护区:当进程因某种原因不能继续占用CPU时,释放CPU,需要将CPU的各种状态信息保护起来。
进程同步与通信机制:用于实现进程间互斥、同步和通信所需的信号量等。
进程所在队列PCB的链接字:根据进程所处的现行状态,进程相应的PCB参加到不同队列中,PCB链接字指出该进程所在队列中下一进程PCB的首地址。
与进程有关的其它信息:如进程记账信息,进程占用CPU的时间等。
进程控制的相关函数
fork()函数
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int count = 0;
pid_t pid;
pid = fork();
if(pid < 0)
{
printf("error in fork!");
exit(1);
}
else if(pid == 0)
printf("I am the child process, the count is %d, my process ID is%d\n", count, getpid());
else
printf("I am the parent process, the count is %d, my process ID is%d\n", ++count, getpid());
return 0;
}
$ ./fork_test
I am the parent process, the count is 1, my process ID is2308
I am the child process, the count is 0, my process ID is2309
父进程中:fork返回新创建的子进程的ID
子进程中:fork返回0
出现错误:fork返回负值
当前进程数已达系统规定的上限,此时errno的值被设置为EAGAIN
系统内存不足,此时errno的值被设置为ENOMEN
vfork()函数
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int count = 1;
int child;
printf("Before create son, the father's count is:%d\n", count);
child = vfork();
if(child < 0)
{
printf("error in vfork!");
exit(1);
}
if(child == 0)
{
printf("This is son, his pid is:%d and the count is:%d\n", getpid(),++ count);
exit(1);
}
else
printf("After son, This is father, his pid is:%d and the count is:%d, and the child is:%d\n", getpid(), count, child);
return 0;
}
$ ./vfork_test1
Before create son, the father's count is:1
This is son, his pid is:2530 and the count is:2
After son, This is father, his pid is:2529 and the count is:2, and the child is:2530
#include <sys/types.h>#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int count = 1;
int child;
printf("Before create son, the father's count is:%d\n", count);
if(!(child = vfork()))
{
int i;
for(i=0; i<100; i++)
{
printf("This is son, the i is:%d\n", i);
if(i == 70)
exit(1);
}
printf("This is son, his pid is:%d and the count is:%d\n", getpid(), ++count);
exit(1);
}
else
printf("After son, This is father, his pid is:%d and the count is:%d, and the child is:%d\n", getpid(), count, child);
return 0;
}
$ ./vfork_test2
Before create son, the father's count is:1
This is son, the i is:0
This is son, the i is:1
This is son, the i is:2
...省略
This is son, the i is:67
This is son, the i is:68
This is son, the i is:69
This is son, the i is:70
After son, This is father, his pid is:2541 and the count is:1, and the child is:2542
exec函数族
#include <unistd.h>
int execl(const char *pathname, const char *arg, ...);
int execlp(const char *filename, const char *arg, ...);
int execle(const char *pathname, const char *arg, ..., 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[]);
函数中含义字母
l
的:其参数个数不定,参数由命令行参数列表组成,最v后一个NULL表示结束。函数中含义字母
v
的:使用一个字符串数组指针argv指向参数列表,与含字母l
的函数参数列表完全相同。函数中含义字母
p
的:可以自动在环境变量PATH指定的路径中搜索要执行的程序,其第一参数filename为可执行函数的文件名,注意其它函数的第一个参数pathname为路径名函数中含义字母
e
的:比其它函数多了一个字符串指针型的envp参数,用于指定环境变量。
#include <stdio.h>
int main(void)
{
char *envp[] = {"PATH=/tmp", "USER=root", "STATUS=testing", NULL};
char *argv_execv[] = {"echo", "excuted by execv", NULL};
char *argv_execvp[] = {"echo", "excuted by execvp", NULL};
char *argv_execve[] = {"env", NULL};
if(fork()==0)
{
if(execl("/bin/echo", "echo", "executed by execl", NULL))
perror("Err on execl");
}
if(fork()==0)
{
if(execlp("echo", "echo", "executed by execlp", NULL))
perror("Err on execlp");
}
if(fork()==0)
{
if(execle("/usr/bin/env", "env", NULL, envp))
perror("Err on execle");
}
if(fork()==0)
{
if(execv("/bin/echo", argv_execv))
perror("Err on execv");
}
if(fork()==0)
{
if(execvp("echo", argv_execvp))
perror("Err on execvp");
}
if(fork()==0)
{
if(execve("/usr/bin/env", argv_execve, envp))
perror("Err on execve");
}
return 0;
}
<pre class="lang_c">
#include <stdio.h>
void perror(const char *s)
```
$ ./exec_example
PATH=/tmp
USER=root
STATUS=testing
executed by execl
executed by execlp
$ PATH=/tmp
USER=root
STATUS=testing
excuted by execvp
excuted by execv
找不到文件或路径:errno被设置为ENOENT
数组argv和envp忘记使用NULL结束:errno被设置为EFAULT
没有文件的运行权限:errno被设置为EACCES
exit()与_exit()函数
#include <stdlib.h>
void exit(int status);
#include <unistd.h>
void _exit(int status);
定义及所需头文件不同
_exit()立即进入内核;exit()则先执行一些清除处理(包括调用执行个终止处理程序,关闭所有标准I/O流等),然后进入内核。
exit()在调用之前要检查文件的打开情况,把文件缓冲区的内容写回文件;_exit()则直接使进程停止,清除其使用的内存空间,并销毁其在内核中的各种数据结构。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
pid_t pid;
if((pid=fork()) == -1)
{
printf("failed to create a new process\n");
exit(0);
}
else if(pid == 0)
{
printf("\nchild process, output begin\n");
printf("child process, content in buffer");
_exit(0);
}
else
{
printf("parent process, output begin\n");
printf("parent process, content in buffer");
exit(0);
}
return 0;
}
$ ./exit_differ
parent process, output begin
parent process, content in buffer
child process, output begin
wait()与waitpid()函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t, int *status, int options);
pid取值 | 含义 |
---|---|
pid > 0 | 只等待进程ID为pid的子线程 |
pid = -1 | 等待任何一个子线程,此时waitpid等价于wait |
pid = 0 | 等待同一个进程组中的任何子进程 |
pid < -1 | 等待一个指定进程组中的任何子进程,其进程ID为pid的绝对值 |
wait()示例
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
pid_t pc, pr;
if((pc = fork()) < 0)
{
printf("error in fork!");
exit(1);
}
else if(pc == 0)
{
printf("This is child process with pid of %d\n", getpid());
sleep(10);
}
else
{
pr = wait(NULL);
printf("I catched a child process with pid of %d\n", pr);
}
exit(0);
}
$ ./wait_example
This is child process with pid of 10093
I catched a child process with pid of 10093
waitpid()示例
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
pid_t pc, pr;
if((pc = fork()) == -1)
{
printf("failed to create a new process");
exit(0);
}
else if(pc == 0)
{
sleep(10);
exit(0);
}
do
{
pr = waitpid(pc, NULL, WNOHANG);
if(pr == 0)
{
printf("No chiled exited\n");
sleep(1);
}
}while(pr == 0);
if(pr == pc)
printf("successfully get child %d\n", pr);
else
printf("some error occured\n");
return 0;
}
$ ./waitpid_example
No chiled exited
No chiled exited
No chiled exited
No chiled exited
No chiled exited
No chiled exited
No chiled exited
No chiled exited
No chiled exited
No chiled exited
successfully get child 2711
获取子进程返回状态
宏定义 | 含义 |
---|---|
WIFEXITED(status) | 子进程正常退出时,返回一个非零值,否则返回零 |
WEXITSTATUS(status) | 当WIFEXITED为真时,此宏才可用,返回该进程退出的代码 |
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int status;
pid_t pc, pr;
if((pc = fork()) < 0)
{
printf("error in fork!");
exit(1);
}
else if(pc == 0)
{
printf("This is child process with pid of %d.\n", getpid());
exit(3);
}
else
{
pr = wait(&status);
if(WIFEXITED(status))
{
printf("the child process %d exit normally.\n", pr);
printf("the return code is %d.\n", WEXITSTATUS(status));
}
else
printf("the child process %d exit abnormally.\n", pr);
}
return 0;
}
$ ./get_status
This is child process with pid of 2718.
the child process 2718 exit normally.
the return code is 3.
system()函数
#include <stdlib.h>
int system(const char *cmdstring);
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int status;
if((status = system(NULL)) < 0)
{
printf("system error!\n");
exit(0);
}
printf("exit status=%d\n", status);
if((status = system("date")) < 0)
{
printf("system error!\n");
exit(0);
}
printf("exit status=%d\n", status);
if((status = system("invalidcommand")) < 0)
{
printf("system error!\n");
exit(0);
}
printf("exit status=%d\n", status);
if((status = system("who; exit 44")) < 0)
{
printf("system error!\n");
exit(0);
}
printf("exit status=%d\n", status);
return 0;
}
$ ./cmd_system
exit status=1
2019年 12月 10日 星期二 14:55:36 CST
exit status=0
sh: 1: invalidcommand: not found
exit status=32512
deeplearning pts/0 2019-12-10 13:46 (192.168.1.110)
exit status=11264
推荐关注????下方公众号学习更多电子技术知识!