标签:style blog http color strong io 文件 数据
1.进程的基本概念
1.1操作系统有三大抽象概念:
a)进程:程序的执行过程;
b)文件: IO;
c)虚拟内存:可用的地址空间;
1.2 进程在内核中是一种数据结构 task_struct(定义见/usr/src/linux-headers-3.8.0-29/include/linux中1240行起)。
1.3 进程由 PCB,代码段以及数据段组成,其中PCB位于内核空间,也就是上述的tsak_struct结构。
1.4 虚拟内存的前面一部分为内核空间(1G),后面是用户空间。
1.5 进程的运行模式有用户态和内核态,以 read 为例,如果接受1000个字节,那么需要进行系统调用,由内核去接收 1000个字节,然后再返回用户态运行 read 的时候,把数据拷贝到用户空间。
1.6 用户态到内核态有两种方式,一是系统调用,触发trap指令陷入内核,二是中断,二者的区别在于前者是自愿的,后者是被动的。
2.进程的状态
2.1 进程的三种经典状态:
a)就绪:准备完毕,随时等待调度;
b)运行:占有CPU;
c)阻塞:等待某一事件的发生。
2.2 三种状态之间的转化:
a)就绪到运行:被CPU调度;
b)运行到阻塞:执行了IO 等需要等待的系统调用,例如read;
c)阻塞到就绪:等待的事件来临,例如read所等待的fd中有数据可读;
d)运行到就绪:时间片到期或者被抢占。
e)这里不存在阻塞到运行:因为调度器总是从就绪队列里面挑选进程。
3.僵尸进程和孤儿进程
3.1 什么是僵尸进程?子进程退出,而父进程没有对其进行回收。这里注意:僵尸进程占用的不是用户空间的资源,子进程运行过程中申请的资源已经全部被回收,占用的是内核中的某些结构,如 PCB,它主要是留给父进程做参考,以便于父进程获取子进程的运行状态。
3.2 僵尸进程程序示例。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/*
* 僵尸进程
*/
int main(int argc, const char *argv[])
{
pid_t pid;
if((pid = fork()) == 0){
printf("in child, pid = %d, parent = %d\n", getpid(), getppid());
}
else{
sleep(20);
printf("in parent, child = %d, pid = %d\n ", pid, getpid());
}
return 0;
}

3.3 孤儿进程:父进程先退出,子进程托管给init进程。
3.4 孤儿进程示例。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/*
* 孤儿进程
*/
int main(int argc, const char *argv[])
{
pid_t pid;
if((pid = fork()) == 0){
printf("in child, pid = %d, parent = %d\n", getpid(), getppid());
sleep(10);
printf("in child, pid = %d, parent = %d\n", getpid(), getppid());
}
else{
sleep(1);
printf("in parent, child = %d, pid = %d\n ", pid, getpid());
}
return 0;
}

4.fork和vfork函数
4.1 利用fork产生的父子进程,地址空间是独立的。因为在传统的UNIX模型中,fork将父进程的地址空间复制了一份给子进程。
4.2 fork程序示例。这里父子进程不共享全局变量,二者是独立的。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0)
/*
* 父子进程的地址空间相互独立
*
*/
int g_val = 10;
int main(int argc, const char *argv[])
{
pid_t pid;
pid = fork();
if(pid == -1){
ERR_EXIT("fork");
}
else if(pid == 0){
sleep(3);
printf("in child ,g_val = %d\n", g_val);
}
else{
g_val++;
printf("in parent, g_val = %d\n", g_val);
}
waitpid(-1, NULL, 0);
return 0;
}
![]()
4.3 vfork 在产生子进程的时候,没有复制地址空间,而是与父进程共享。vfork的目的就是为了在子进程中实行exec替换。程序示例如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); }while(0)
/*
* vfork
*/
int g_val = 10;
int main(int argc, const char *argv[])
{
pid_t pid;
pid = vfork();
if(pid == -1){
ERR_EXIT("fork");
}
else if(pid > 0){
sleep(3);
printf("in parent ,g_val = %d\n", g_val);
}
else{
g_val++;
printf("in child, g_val = %d\n", g_val);
exit(EXIT_SUCCESS); //若不加 子进程会一直在父进程空间中执行
}
return 0;
}
5.atexit函数
5.1 atexit 的作用是向系统注册一些函数,这些函数在程序退出的时候被调用,并且这些函数被调用的顺序与注册的顺序相反。程序示例如下。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void test1(){
printf("test1...\n");
}
void test2(){
printf("test2...\n");
}
void test3(){
printf("test3...\n");
}
int main(int argc, const char *argv[])
{
atexit(test1);
atexit(test2);
atexit(test3);
printf("before return \n");
return 0;
}
5.2 exit 和 _exit 的区别
a)exit 会清空 IO 缓冲区,后者不会;
b)exit 会处理通过 atexit 注册的函数。
0724------Linux基础----------进程1,布布扣,bubuko.com
0724------Linux基础----------进程1
标签:style blog http color strong io 文件 数据
原文地址:http://www.cnblogs.com/monicalee/p/3869228.html