Linux下的C编程实战之三.doc

上传人:asd****56 文档编号:70344455 上传时间:2023-01-19 格式:DOC 页数:10 大小:58.50KB
返回 下载 相关 举报
Linux下的C编程实战之三.doc_第1页
第1页 / 共10页
Linux下的C编程实战之三.doc_第2页
第2页 / 共10页
点击查看更多>>
资源描述

《Linux下的C编程实战之三.doc》由会员分享,可在线阅读,更多相关《Linux下的C编程实战之三.doc(10页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、Linux下的C编程实战之三1.Linux进程Linux进程在内存中包含三部分数据:代码段、堆栈段和数据段。代码段存放了程序的代码。代码段可以为机器中运行同一程序的数个进程共享。堆栈段存放的是子程序(函数)的返回地址、子程序的参数及程序的局部变量。而数据段则存放程序的全局变量、常数以及动态数据分配的数据空间(比如用malloc函数申请的内存)。与代码段不同,如果系统中同时运行多个相同的程序,它们不能使用同一堆栈段和数据段。Linux进程主要有如下几种状态:用户状态(进程在用户状态下运行的状态)、内核状态(进程在内核状态下运行的状态)、内存中就绪(进程没有执行,但处于就绪状态,只要内核调度它,就

2、可以执行)、内存中睡眠(进程正在睡眠并且处于内存中,没有被交换到SWAP设备)、就绪且换出(进程处于就绪状态,但是必须把它换入内存,内核才能再次调度它进行运行)、睡眠且换出(进程正在睡眠,且被换出内存)、被抢先(进程从内核状态返回用户状态时,内核抢先于它,做了上下文切换,调度了另一个进程,原先这个进程就处于被抢先状态)、创建状态(进程刚被创建,该进程存在,但既不是就绪状态,也不是睡眠状态,这个状态是除了进程0以外的所有进程的最初状态)、僵死状态(进程调用exit结束,进程不再存在,但在进程表项中仍有记录,该记录可由父进程收集)。下面我们来以一个进程从创建到消亡的过程讲解Linux进程状态转换的

3、“生死因果”。(1)进程被父进程通过系统调用fork创建而处于创建态;(2)fork调用为子进程配置好内核数据结构和子进程私有数据结构后,子进程进入就绪态(或者在内存中就绪,或者因为内存不够而在SWAP设备中就绪);(3)若进程在内存中就绪,进程可以被内核调度程序调度到CPU运行;(4)内核调度该进程进入内核状态,再由内核状态返回用户状态执行。该进程在用户状态运行一定时间后,又会被调度程序所调度而进入内核状态,由此转入就绪态。有时进程在用户状态运行时,也会因为需要内核服务,使用系统调用而进入内核状态,服务完毕,会由内核状态转回用户状态。要注意的是,进程在从内核状态向用户状态返回时可能被抢占,这

4、是由于有优先级更高的进程急需使用CPU,不能等到下一次调度时机,从而造成抢占;(5)进程执行exit调用,进入僵死状态,最终结束。2.进程控制进程控制中主要涉及到进程的创建、睡眠和退出等,在Linux中主要提供了fork、exec、clone的进程创建方法,sleep的进程睡眠和exit的进程退出调用,另外Linux还提供了父进程等待子进程结束的系统调用wait。fork对于没有接触过Unix/Linux操作系统的人来说,fork是最难理解的概念之一,它执行一次却返回两个值,完全“不可思议”。先看下面的程序:int main()int i;if (fork() = 0)for (i = 1;

5、i 3; i+)printf(This is child processn);elsefor (i = 1; i 3; i+)printf(This is parent processn);执行结果为:This is child processThis is child processThis is parent processThis is parent processfork在英文中是“分叉”的意思,这个名字取得很形象。一个进程在运行中,如果使用了fork,就产生了另一个进程,于是进程就“分叉”了。当前进程为父进程,通过fork()会产生一个子进程。对于父进程,fork函数返回子程序的进程

6、号而对于子程序,fork函数则返回零,这就是一个函数返回两次的本质。可以说,fork函数是Unix系统最杰出的成就之一,它是七十年代Unix早期的开发者经过理论和实践上的长期艰苦探索后取得的成果。如果我们把上述程序中的循环放的大一点:int main()int i;if (fork() = 0)for (i = 1; i 10000; i+)printf(This is child processn);elsefor (i = 1; i 10000; i+)printf(This is parent processn);则可以明显地看到父进程和子进程的并发执行,交替地输出“This is ch

7、ild process”和“This is parent process”。此时此刻,我们还没有完全理解fork()函数,再来看下面的一段程序,看看究竟会产生多少个进程,程序的输出是什么?int main()int i;for (i = 0; i );fgets(command, MAX_CMD_LEN, stdin);commandstrlen(command) - 1 = 0;if (fork() = 0)/* 子进程执行此命令 */execlp(command, command);/* 如果exec函数返回,表明没有正常执行命令,打印错误信息*/perror(command);exit(

8、errorno);else/* 父进程,等待子进程结束,并打印子进程的返回值 */wait(&rtn);printf( child process return %dn, rtn);这个函数基本上实现了一个shell的功能,它读取用户输入的进程名和参数,并启动对应的进程。cloneclone是Linux2.0以后才具备的新功能,它较fork更强(可认为fork是clone要实现的一部分),可以使得创建的子进程共享父进程的资源,并且要使用此函数必须在编译内核时设置clone_actually_works_ok选项。clone函数的原型为:int clone(int (*fn)(void *),

9、void *child_stack, int flags, void *arg);此函数返回创建进程的PID,函数中的flags标志用于设置创建子进程时的相关选项,具体含义如下表:标志含义CLONE_PARENT创建的子进程的父进程是调用者的父进程,新进程与创建它的进程成了“兄弟”而不是“父子”CLONE_FS子进程与父进程共享相同的文件系统,包括root、当前目录、umaskCLONE_FILES子进程与父进程共享相同的文件描述符(file descriptor)表CLONE_NEWNS在新的namespace启动子进程,namespace描述了进程的文件hierarchyCLONE_SIG

10、HAND子进程与父进程共享相同的信号处理(signal handler)表CLONE_PTRACE若父进程被trace,子进程也被traceCLONE_VFORK父进程被挂起,直至子进程释放虚拟内存资源CLONE_VM子进程与父进程运行于相同的内存空间CLONE_PID子进程在创建时PID与父进程一致CLONE_THREADLinux 2.4中增加以支持POSIX线程标准,子进程与父进程共享相同的线程群来看下面的例子:int variable, fd; int do_something() variable = 42;close(fd);_exit(0);int main(int argc,

11、char *argv) void *child_stack;char tempch;variable = 9;fd = open(test.file, O_RDONLY);child_stack = (void *) malloc(16384);printf(The variable was %dn, variable);clone(do_something, child_stack, CLONE_VM|CLONE_FILES, NULL);sleep(1); /* 延时以便子进程完成关闭文件操作、修改变量*/printf(The variable is now %dn, variable);

12、if (read(fd, &tempch, 1) 0)printf(received from pipe: %sn, buf);fclose(in_file);/* 进程二:写有名管道*/void main()FILE *out_file;int count = 1;char bufBUFFER_LEN;out_file = fopen(pipeexample, w);if (out_file = NULL)printf(Error opening pipe.);exit(1);sprintf(buf, this is test data for the named pipe examplen

13、);fwrite(buf, 1, BUFFER_LEN, out_file);fclose(out_file);消息队列用于运行于同一台机器上的进程间通信,与管道相似;共享内存通常由一个进程创建,其余进程对这块内存区进行读写。得到共享内存有两种方式:映射/dev/mem设备和内存映像文件。前一种方式不给系统带来额外的开销,但在现实中并不常用,因为它控制存取的是实际的物理内存;常用的方式是通过shmXXX函数族来实现共享内存:int shmget(key_t key, int size, int flag);/* 获得一个共享存储标识符 */该函数使得系统分配size大小的内存用作共享内存;vo

14、id *shmat(int shmid, void *addr, int flag); /* 将共享内存连接到自身地址空间中*/shmid为shmget函数返回的共享存储标识符,addr和flag参数决定了以什么方式来确定连接的地址,函数的返回值即是该进程数据段所连接的实际地址。此后,进程可以对此地址进行读写操作访问共享内存。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。一般说来,为了获得共享资源,进程需要执行下列操作: (1)测试控制该资源的信号量;(2)若此信号量的值为正,则允许进行使用该资源,进程将进号量减1; (3)若此信号量为0,则该资源目前不可用,进程进

15、入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1); (4)当进程不再使用一个信号量控制的资源时,信号量值加1,如果此时有进程正在睡眠等待此信号量,则唤醒此进程。 下面是一个使用信号量的例子,该程序创建一个特定的IPC结构的关键字和一个信号量,建立此信号量的索引,修改索引指向的信号量的值,最后清除信号量:#include #include #include #include void main()key_t unique_key; /* 定义一个IPC关键字*/int id;struct sembuf lock_it;union semun options;int i;unique_k

16、ey = ftok(., a); /* 生成关键字,字符a是一个随机种子*/* 创建一个新的信号量集合*/id = semget(unique_key, 1, IPC_CREAT | IPC_EXCL | 0666);printf(semaphore id=%dn, id);options.val = 1; /*设置变量值*/semctl(id, 0, SETVAL, options); /*设置索引0的信号量*/*打印出信号量的值*/i = semctl(id, 0, GETVAL, 0);printf(value of semaphore at index 0 is %dn, i);/*下

17、面重新设置信号量*/lock_it.sem_num = 0; /*设置哪个信号量*/lock_it.sem_op = - 1; /*定义操作*/lock_it.sem_flg = IPC_NOWAIT; /*操作方式*/if (semop(id, &lock_it, 1) = - 1)printf(can not lock semaphore.n);exit(1);i = semctl(id, 0, GETVAL, 0);printf(value of semaphore at index 0 is %dn, i);/*清除信号量*/semctl(id, 0, IPC_RMID, 0);套接字通信并不为Linux所专有,在所有提供了TCP/IP协议栈的操作系统中几乎都提供了socket,而所有这样操作系统,对套接字的编程方法几乎是完全一样的。4.小节本章讲述了Linux进程的概念,并以多个实例讲解了进程控制及进程间通信方法,理解这一章的内容可以说是理解Linux这个操作系统的关键。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁