现任职北京某互联网公司运维经理,高级架构师,涉足互联网运维行业已经超过10年。曾服务于京东商城,互动百科等互联网公司,早期运维界新星。 长期专研,C语言开发,操作系统内核,大型互联网架构。http://www.bdkyr.com
全部博文(166)
分类: 系统运维
2015-01-22 00:01:27
一、进程的概念
首先了解,什么是进程?
Linux 操作系统是面向多用户的.在同一时间可以有许多用户向操作系统发出各种命令.那么操作系统是怎么实现多用户的环境呢? 在现代的操作系统里面,都有程序和进程的概念。那么什么是程序,什么是进程呢? 通俗的讲程序是一个包含可以执行代码的文件,是一个静态的文件,而进程是一个开始执行但是还没有结束的程序的实例.就是可执行文件的具体实现.。一个程序可能有许多进程,而每一个进程又可以有许多子进程.依次循环下去,而产生子孙进程。当程序被系统调用到内存以后,系统会给程序分配一定的资源(内存,设备等等)然后进行一系列的复杂操作,使程序变成进程以供系统调用。在系统里面只有进程没有程序,为了区分各个不同的进程,系统给每一个进程分配了一个ID(就象我们的身份证)以便识别。为了充分的利用资源,系统还对进程区分了不同的状态。将进程分为新建、运行、阻塞、就绪和完成五个状态。新建表示进程正在被创建,运行是进程正在运行,阻塞是进程正在等待某一个事件发生,就绪是表示系统正在等待CPU 来执行命令,而完成表示进程已经结束了系统正在回收资源。
二、进程的标志上面我们知道了进程都有一个ID,那么我们怎么得到进程的ID 呢?系统调用getpid 可以得到进程的ID,而getppid 可以得到父进程(创建调用该函数进程的进程)的ID.
#include
pid_t getpid(void);
pid_t getppid(void);
进程是为程序服务的,而程序是为了用户服务的。系统为了找到进程的用户名,还为进程和用户建立联系。这个用户称为进程的所有者。相应的每一个用户也有一个用户ID。通过系统调用getuid 可以得到进程的所有者的ID。由于进程要用到一些资源,而Linux 对系统资源是进行保护的,为了获取一定资源进程还有一个有效用户ID。这个ID 和系统的资源使用有关,涉及到进程的权限.,通过系统调用geteuid 我们可以得到进程的有效用户ID.。和用户ID相对应进程还有一个组ID 和有效组ID 系统调用getgid 和getegid 可以分别得到组ID 和有效组ID
三、进程的创建创建一个进程的系统调用很简单.我们只要调用fork 函数就可以了.
#include
pid_t fork();
当一个进程调用了fork 以后,系统会创建一个子进程.这个子进程和父进程不同的地方只有他的进程ID 和父进程ID,其他的都是一样.就象符进程克隆(clone)自己一样。当然创建两个一模一样的进程是没有意义的。为了区分父进程和子进程,我们必须跟踪fork 的返回值.。当fork 掉用失败的时候(内存不足或者是用户的最大进程数已到)fork 返回-1,否则fork 的返回值有重要的作用.对于父进程fork 返回子进程的ID,而对于fork 子进程返回0。我们就是根据这个返回值来区分父子进程的,父进程为什么要创建子进程呢?前面我们已经说过了Linux 是一个多用户操作系统,在同一时间会有许多的用户在争夺系统的资源.有时进程为了早一点完成任务就创建子进程来争夺资源。一旦子进程被创建,父子进程一起从fork 处继续执行,相互竞争系统的资源.有时候我们希望子进程继续执行,而父进程阻塞直到子进程完成任务。这个时候我们可以调用wait 或waitpid 系统调用。
Fork函数被调用一次,但返回两次。两次返回的唯一区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程ID。子进程获得父进程数据空间、堆和栈的副本。注意,这是子进程所拥有的副本。父子进程并不共享这些存储空间部分。/*
* create by bdkyr
*date 2015-1-21
*/
#include
#include
#include
#include
#include
#include
#define MAXLINE 4096 /* max line length */
int glob = 6;
char buf[]= "a write to stdout\n";
void err_sys(const char *fmt, ...);
static void err_doit(int, int, const char *, va_list);
int main(void){
int var;
pid_t pid;
var = 88;
if (write (STDOUT_FILENO, buf, sizeof(buf) -1) != sizeof(buf)-1)
err_sys("write error");
printf("before fork\n");
if((pid = fork()) < 0){
err_sys("fork error");
}else if(pid == 0){
glob++;
var++;
}else{
sleep(2);
}
printf("pid=%d, glob = %d, var = %d\n", getpid(),glob, var);
exit(0);
}
void err_sys(const char *fmt, ...){
va_list ap;
va_start(ap, fmt);
err_doit(1, errno, fmt, ap);
va_end(ap);
exit(1);
}
static void err_doit(int errnoflag, int error, const char *fmt, va_list ap){
vsnprintf(buf, MAXLINE, fmt, ap);
if(errnoflag)
snprintf(buf+strlen(buf), MAXLINE-strlen(buf), ": %s", strerror(error));
strcat(buf, "\n");
fflush(stdout);
fputs(buf, stderr);
fflush(NULL);
}
[root@test bdkyr]# gcc fork_test.c -o fork_test
[root@test bdkyr]# ./fork_test
a write to stdout
before fork
pid=5209, glob = 7, var = 89
pid=5208, glob = 6, var = 88
五、总结
说到底,多进程我们可以简单理解为,一个进程表示的,就是一个可执行程序的一次执行过程中的一个状态。操作系统对进程的管理,典型的情况,是通过进程表完成的。进程表中的每一个
表项,记录的是当前操作系统中一个进程的情况。对于单 CPU的情况而言,每一特定时刻只有一个进程占用
CPU,但是系统中可能同时存在多个活动的(等待执行或继续执行的)进程。fork()用于从已存进程中建立一个新进程,新进程为子进程,老进程为父进程.可以通过检查"fork()"地返回值知道哪个是子进程哪个是父进程。父进程得到的返回值是子进程的进程号,而子进程则返回0。
您有收获吗?