实验2-进程的初步认识 下载本文

实验二:进程的初步认识实验

实验学时:2学时 一、

实验目的

(1) 掌握进程的概念

(2) 掌握系统调用

(3)设计程序,实现结果的不可再现性;使用同步原语,实现结果的可再现性 (4)设计程序,对系统的进程数目进行压力测试,对运行时间进行监控 二、实验基本原理 1.简单的系统调用

(1) fork();当fork()函数返回值为0时,子进程成功创建,以下为子进程作用域 头文件:

#include

#include 函数原型:

pid_t fork( void);

(pid_t 是一个宏定义,其实质是int 被定义在#include中)

返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1

函数说明:

一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。

子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。 linux将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。

fork()在Linux系统中的返回值是没有NULL的. Error Codes

出错返回错误信息如下: EAGAIN

达到进程数上限.

ENOMEM

没有足够空间给一个新进程分配.

(2)syscall(SYS_getpid);调用系统函数syscall(),返回当前进程号 (3)getpid();调用系统函数getpid(),返回当前进程号 (4)getppid();获得父进程id号 (5)execl( );

头文件:#include

原型:int execl(const char *path, const char *arg, ...);

函数说明:execl()用来执行参数path字符串所代表的文件路径, 接下来的参数代表执行该文件时传递的argv[0],argv[1].....是后一个参数必须用空指针NULL作结束 返回值:成功则不返回值, 失败返回-1,失败原因存于errno中 2.linux的进程同步原语

(1)wait();

函数原型:

#include #include pid_t wait(int *status);

进程一旦调用了wait就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。

参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL,就像下面这样: pid = wait(NULL);

如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。 (2)#include

#include

key_t ftok (char*pathname, char proj); 它返回与路径pathname相对应的一个键值。

(3)int semget(key_t key, int nsems, int semflg)

参数key是一个键值,由ftok获得,唯一标识一个信号灯集,用法与msgget()中的key相同;参数nsems指定打开或者新创建的信号灯集中将包含信号灯的数目;semflg参数是一些标志位。参数key和semflg的取值,以及何时打开已有信号灯集或者创建一个新的信号灯集与msgget()中的对应部分相同,不再祥述。该调用返回与健值key相对应的信号灯集描述字。调用返回:成功返回信号灯集描述字,否则返回-1。

注:如果key所代表的信号灯已经存在,且semget指定了IPC_CREAT|IPC_EXCL标志,那么即使参数nsems与原来信号灯的数目不等,返回的也是EEXIST错误;如果semget只指定了IPC_CREAT标志,那么参数nsems必须与原来的值一致,在后面程序实例中还要进一步说明。 (4)int semop(int semid, struct sembuf *sops, unsigned nsops);

semid是信号灯集ID,sops指向数组的每一个sembuf结构都刻画一个在特定信号灯上的操作。nsops为sops指向数组的大小。

(5)int semctl(int semid,int semnum,int cmd,union semun arg)

该系统调用实现对信号灯的各种控制操作,参数semid指定信号灯集,参数cmd指定具体的操作类型;参数semnum指定对哪个信号灯操作,只对几个特殊的cmd操作有意义;arg用于设置或返回信号灯信息。

该系统调用详细信息请参见其手册页,这里只给出参数cmd所能指定的操作。 IPC_STAT 获取信号灯信息,信息由arg.buf返回; IPC_SET

设置信号灯信息,待设置信息保存在arg.buf中(在manpage中给出了可以设置哪些信息);

GETALL 返回所有信号灯的值,结果保存在arg.array中,参数sennum被忽略; GETNCNT

返回等待semnum所代表信号灯的值增加的进程数,相当于目前有多少进程在等待semnum代表的信号灯所代表的共享资源;

GETPID 返回最后一个对semnum所代表信号灯执行semop操作的进程ID; GETVAL 返回semnum所代表信号灯的值;

GETZCNT 返回等待semnum所代表信号灯的值变成0的进程数; SETALL

通过arg.array更新所有信号灯的值;同时,更新与本信号集相关的semid_ds结构的sem_ctime成员;

SETVAL 设置semnum所代表信号灯的值为arg.val;

二、

参考程序

0. 创建进程示例 示例代码:

#include //对于此程序而言此头文件用不到 #include #include

int main(int argc, char ** argv ) {

int pid = fork(); if (pid < 0) {

printf(\ }

else if( pid == 0 ) {

printf(\ } else{

printf(\ } return 0; }

1.程序的不可再现性: $cat tc_print.c #include

int main(int argc,char *argv[]) {

printf(\ sleep(3);

printf(\

return(0); }