【APUE】笔记之——进程控制

《APUE》第八章,之进程控制笔记。

1. 进程标识符

     Unix/Linux中每个进程都有一个非负整数表示的唯一进程ID。ID唯一,但可以重用,大多数unix使用延迟重用算法,使得赋予新建进程的ID不同于最近终止进程所使用的ID。

    系统中有一些专用进程。ID为0的进程是调度进程,常常被称为交换进程。该进程是内核的一部分。进程ID是1的通常是init进程,在自举过程结束时有内核调用,负责在自举内核后启动unix系统。init进程决不会终止,但它是一个普通的用户进程,以超级用户特权运行。init一个特殊的地方是,它会成为所有孤儿进程的父进程。某些unix系统,进程ID 2是页守护进程,负责支持虚拟存储系统的分页操作。

    与进程标志符有关的系统调用主要有:

#inclue <unistd.h>
pid_t getpid(void);    返回调用进程的ID
pid_t getppid(void);   返回调用进程父进程的ID
uid_t getuid(void);    返回调用进程的实际用户ID
uid_t geteuid(void);    返回调用进程的有效用户ID
gid_t getgid(void);    返回调用进程的组ID
git_t getegid(void);   返回调用进程的有效组ID








2. fork函数

    fork函数创建一个新的进程。函数原型如下:

    

#include <unistd.h>
 pid_t fork(void);

返回值:子进程中返回0,父进程返回子进程ID,出错返回-1

    fork函数被调用一次,但返回两次,两次返回的唯一区别是子进程的返回值是0,父进程的返回值是新子进程的ID。将子进程ID返回给父进程的理由是:一个进程的子进程可能有多个,而且没有一个函数是一个进程可以获得其所有子进程的ID。

    子进程和父进程继续执行fork调用之后的指令。子进程是父进程的副本。例如,子进程获得父进程数据空间、队和栈的副本。注意这是子进程所拥有的副本。父、子进程并不共享这些存储空间,父子进程共享正文段。由于在fork之后进场跟随着exec,所以很多的实现并不执行一个父进程数据空间的完全复制,而是采用写时复制(copy-on-write,COW)策略。父子进程共享的部分的访问权限是只读的,如果父子进程中的任一个试图修改共享部分,则内核之为修改区域的那块内存制作一个副本。通常是存储器系统的一“页”。


    实例:

#include <unistd.h>
#include <stdio.h>
int glob = 6;
char buf[] = "a write to stdout\n";
int main(int argc, char const *argv[])
{
	int var;
	pid_t pid;

	var = 88;

	printf("parent PID %d\n", getpid());
	printf("before fork:\n");


	if((pid = fork()) < 0) //create new child process
	{
		printf("fork error!\n");
		exit(0);
	}
	else if (pid == 0)
	{
		/* child */
		glob++;
		var++;
	}
	else 
	{
		/* parent */
		sleep(2);
	}

	printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);

	return 0;
}

运行结果如下:

$ ./fork
parent PID 3757
before fork:
pid = 3758, glob = 7, var = 89
pid = 3757, glob = 6, var = 88

    一般来说,fork之后父进程先执行还是子进程先执行是不确定的,取决于内核的调度算法。如果要求父子进程之间同步,需要某种形式的进程同步通信,后面会讲到。

   这里需要特别注意的是,fork与I/O函数之间交互关系,也就是fork前后的printf缓冲问题。注意fork之前的printf语句,printf是标准的输出函数,是带缓冲的。Unix中,如果标准输出连接到设备终端,则它是行缓冲的,否则他就是全缓冲的。换句话说,行缓冲就是遇到换行才会把缓冲区的内容打印到屏幕上;而全缓冲只有等到缓冲区满或者程序退出才把内容写到目的设备上。当我们直接运行该程序不进行输出重定向时,只得到printf输出的行内容一次,其原因是在fork之前,标准输出的缓冲区的内容已经由换行符冲洗。但是当标准输出重定向到一个文件时,却得到printf输出两次。其原因是,在fork之前调用了printf,但是执行fork时,该数据仍然在缓冲区(全缓冲),然后在将父进程的数据空间复制到子进程是,该缓冲区也被复制到子进程中,所以父子进程各自有了带有该行内容的缓冲区。因此printf的内容会被输出两次。

    比如:我们使用 ./fork > a.out 运行上面的程序,所有fork之前printf的内容都会在a.out中出现两次,这就是由于全缓冲的原因。 

再有我们将

printf("before fork:\n");

的换行符 \n 去掉,使用 ./fork 运行,则结果中该语句会输出两次。因为没有了换行符,这条语句的打印内容会被缓冲,然后缓冲区被复制到子进程,从而输出两次。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值