程序就是一堆待执行的代码。 -> 静态的文本数据。 例如: project.c(C语言程序) / project(可执行程序)。
进程就是当程序被CPU加载,根据每一行代码做出相应的效果,才能形成一个动态的过程,这个过程就称之为进程。
直接在linux下执行程序即可。
例如: ./project -> 开启一个新的进程!
结构体在哪里?
Ubuntu: /usr/src/linux-headers-3.5.0-23/include/linux/sched.h
struct task_struct {
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ -> 进程运行状态。
void *stack;
....
struct uprobe_task *utask;
int uprobe_srcu_id;
#endif
};
gec@ubuntu:~$ ps -ef
用户名 PID PPID 创建时间 持续时间 进程名字
root 1 0 0 16:37 ? 00:00:00 /sbin/init -> 祖先进程
gec 2272 1 0 16:37 ? 00:00:01 gnome-terminal -> linux终端
gec 2278 2272 0 16:37 pts/1 00:00:00 bash -> linux终端的子进程,叫bash进程
gec 2720 2278 0 18:54 pts/1 00:00:00 ps -ef -> bash进程的子进程,shell命令
gec@ubuntu:~$ top
Tasks: 150 total -> 当前系统有150个进程
2 running -> 2个在运行态
148 sleeping -> 148个睡眠态
0 stopped -> 0个暂停态
0 zombie -> 0个僵尸态
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1049 root 20 0 96160 26m 6700 S 5.3 2.6 0:18.50 Xorg
S -> state当前进程状态
%CPU -> 当前瞬间CPU占用率
%MEM -> 当前瞬间内存占用率
gec@ubuntu:~$ pstree
init─┬─NetworkManager───{NetworkManager}
├─accounts-daemon───{accounts-daemon}
├─acpid
├─gnome-terminal─┬─bash───pstree
进程生老病死就是从进程开启到进程结束经历所有状态。
就是进程自身的资源(任务结构体)没有释放。
进程结束时,一定会切换到僵尸态。所谓僵尸态,就是本进程已经结束,但是自身的资源还没有释放掉。
详细见:"进程的生老病死.jpg"
单进程程序 -> 只能一行一行代码去执行。
创建子进程意义: 同时处理多个任务。
#include <unistd.h>
pid_t fork(void);
参数:无
成功:
父进程 -> 子进程的PID号 >0
子进程 -> 0
失败:
父进程 -> -1
没有创建出子进程。
例题: 在进程内部创建一个新的子进程,看看会不会同时处理两件事情。
#include <unistd.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
/* 现在只有一个进程,就是父进程 */
printf("hello\n");
printf("world\n");
fork();
/* 到这里为止,就有两个进程 */
printf("appletree\n");
return 0;
}
gec@ubuntu:/mnt/hgfs/GZ1934/09 系统编程/01/code$ ./fork_test
hello
world
appletree -> 父进程打印
gec@ubuntu:/mnt/hgfs/GZ1934/09 系统编程/01/code$ appletree -> 子进程打印
gec@ubuntu:/mnt/hgfs/GZ1934/09 系统编程/01/code$ ./fork_test
hello
world
appletree -> 子进程打印
appletree -> 父进程打印
gec@ubuntu:/mnt/hgfs/GZ1934/09 系统编程/01/code$
练习1: 写一个程序,使得子进程先打印apple,父进程再打印hello。
#include <unistd.h>
#include <stdio.h>
int main()
{
/* 父进程 */
pid_t x;
x = fork();
/* 父进程 */ /* 子进程 */
//返回值情况: x > 0 x = 0
if(x > 0) //父进程
{
usleep(5000);
printf("hello!\n");
}
if(x == 0) //子进程
{
printf("apple!\n");
}
return 0;
}
getpid() getppid() -> man 2 getpid
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
getpid()
成功: 当前进程的ID号
失败: 不存在的!
getppid()
成功: 当前进程的PID号
失败: 不存在的!
练习2: 在子进程中打印自己与父进程的ID号,在父进程中打印自己与子进程的ID,通过ps -ef命令查看ID是否一致!
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t x;
x = fork();
if(x > 0) //父
{
usleep(10000);
printf("parent pid = %d\n",getpid());
printf("child pid = %d\n",x);
}
if(x == 0) //子
{
printf("child pid = %d\n",getpid());
printf("parent pid = %d\n",getppid());
}
return 0;
}
练习3: 验证孤儿进程会马上寻找继父,而不是等到孤儿进程结束才找。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
pid_t x;
x = fork();
if(x > 0)
{
sleep(2);
}
if(x == 0)
{
printf("parent pid = %d\n",getppid());
sleep(3);
printf("parent pid = %d\n",getppid());
printf("helloworld!\n");
sleep(1);
printf("appletree!\n");
}
return 0;
}
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
status:储存子进程退出状态的指针。
填NULL,代表父进程不关心子进程的退出状态。
不填NULL,代表父进程想知道子进程的退出状态。
成功: 退出的子进程的ID号
失败: -1
练习4: 验证wait()可以帮子进程回收资源。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t x;
x = fork();
if(x > 0)
{
sleep(10); //有1个僵尸
wait(NULL); //僵尸态 -> 死亡态
sleep(8); //有0个僵尸
}
if(x == 0)
{
printf("hello!\n"); //运行态 -> 僵尸态
}
return 0;
}
举例子。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t x;
x = fork();
if(x == 0)
{
printf("parent pid = %d\n",getppid());
printf("child helloworld!\n");
//printf("parent pid = %d\n",getppid());
} //子进程: 运行态 -> 僵尸态
if(x > 0)
{
sleep(15); //1个僵尸态
printf("parent helloworld!\n");
sleep(3);
printf("parent exit!\n"); //子进程就会寻找继父,帮自己回收资源。
}
return 0;
}
举例子。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
pid_t x;
x = fork();
if(x > 0)
{
sleep(2);
}
if(x == 0)
{
printf("parent pid = %d\n",getppid());
sleep(3);
printf("parent pid = %d\n",getppid());
printf("helloworld!\n");
sleep(10); -> 在这10秒内,子进程继父就是祖先进程。
printf("appletree!\n");
-> 子进程结束,让继父帮子进程回收资源。
}
return 0;
}
exit() -> 查询: man 3 exit
#include <stdlib.h>
void exit(int status);
status: 退出的状态
0 -> 正常退出
非0 -> 异常退出
_exit() -> 查询: man 2 _exit
_Exit() -> 查询: man 2 _Exit
#include <unistd.h>
void _exit(int status);
#include <stdlib.h>
void _Exit(int status);
status: 退出的状态
0 -> 正常退出
非0 -> 异常退出
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("hello");
exit(0); //输出hello,再退出!
_exit(0); //不输出hello,直接退出!
printf("world"); //无论什么退出函数,都不会运行到这里。
return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t x;
int state;
x = fork();
if(x > 0)
{
wait(&state);
printf("state = %d\n",state);
}
if(x == 0)
{
sleep(5);
exit(0); //这个exit(0)只是说明子进程退出。
}
return 0;
}
举例子。
void fun()
{
//return; -> 效果:就会打印hello
exit(0); -> 效果:不会打印hello
}
int main()
{
fun();
printf("hello!\n");
return 0;
}
举例子。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc,char *argv[])
{
int a = 100;
pid_t x;
x = fork();
if(x > 0)
{
//int a = 100;
sleep(1);
printf("parent a = %d\n",a); //100
}
if(x == 0)
{
a = 50;
printf("child a = %d\n",a); //50
}
return 0;
}
#include <unistd.h>
int execl(const char *path, const char *arg, ...);
path: 需要执行的那个程序的名字,例如: /home/gec/project
arg: 需要运行时传递的参数,例如: "project","aaa",NULL
成功: 非-1
失败: -1
例子: 产生一个子进程,让子进程执行"ls -l"这个程序。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc,char *argv[])
{
pid_t x;
x = fork();
if(x > 0)
{
sleep(2);
printf("I am parent!\n");
}
if(x == 0)
{
printf("apple tree!\n");
execl("/bin/ls","ls","-l",NULL);
printf("helloworld!\n"); -> exec函数族替换掉一个程序,子进程之后的代码都不会执行。
}
return 0;
}
[root@GEC6818 /]#madplay jay.mp3
MPEG Audio Decoder 0.15.2 (beta) - Copyright (C) 2000-2004 Robert Leslie et al.
Title: ····
Artist: ···
Album: ········
原文:https://www.cnblogs.com/zjlbk/p/11322760.html