信阳如何在c语言中调用Linux脚本

如何在c言语中调用Linux脚本呢?你知道如何在c言语中调用Linux脚本吗?下面是小编为大家带来的如何在c言语中调用Linux脚本的知识,欢迎阅读。

一、引言

关于没有接触过Unix/Linux操作系统的人来说,fork是最难了解的概念之一:它执行一次却前往两个值。fork函数是Unix系统最出色的成就之一,它是七十年代UNIX早期的开发者经过临时在实际和实际上的艰辛探求后取得的效果,一方面,它使操作系统在进程管理上付出了最小的代价,另一方面,又为顺序员提供了一个繁复明了的多进程方法。与DOS和早期的Windows不同,Unix/Linux系统是真正完成多义务操作的系统,可以说,不运用多进程编程,就不能算是真正的Linux环境下编程。多线程顺序设计的概念早在六十年代就被提出,但直到八十年代中期,Unix系统中才引入多线程机制,如今,由于自身的许多优点,多线程编程曾经失掉了普遍的运用。下面,我们将引见在Linux下编写多进程和多线程顺序的一些初步知识。

二、多进程编程

什么是一个进程?进程这个概念是针对系统而不是针对用户的,对用户来说,他面对的概念是顺序。当用户敲入命令执行一个顺序的时分,对系统而言,它将启动一个进程。但和顺序不同的是,在这个进程中,系统能够需求再启动一个或多个进程来完成独立的多个义务。多进程编程的主要内容包括进程控制和进程间通讯,在了解这些之前,我们先要复杂知道进程的结构。

2.1 Linux下进程的结构

Linux下一个进程在内存里有三局部的数据,就是“代码段”、“堆栈段”和“数据段”。其实学过汇编言语的人一定知道,普通的CPU都有上述三种段寄存器,以方便操作系统的运转。这三个局部也是构成一个完整的执行序列的必要的局部。

“代码段”,望文生义,就是寄存了顺序代码的数据,假设机器中有数个进程运转相反的一个顺序,那么它们就可以运用相反的代码段。“堆栈段”寄存的就是子顺序的前往地址、子顺序的参数以及顺序的局部变量。而数据段则寄存顺序的全局变量,常数以及静态数据分配的数据空间(比如用malloc之类的函数取得的空间)。这其中有许多细节效果,这里限于篇幅就不多引见了。系统假设同时运转数个相反的顺序,它们之间就不能运用同一个堆栈段和数据段。

2.2 Linux下的进程控制

在传统的Unix环境下,有两个基本的操作用于创立和修正进程:函数fork( )用来创立一个新的进程,该进程简直是当行进程的一个完全拷贝;函数族exec( )用来启动另外的进程以取代以后运转的进程。Linux的进程控制和传统的Unix进程控制基本分歧,只在一些细节的中央有些区别,例如在Linux系统中调用vfork和fork完全相反,而在有些版本的Unix系统中,vfork调用有不同的功用。由于这些差异简直不影响我们大少数的编程,在这里我们不予思索

2.2.1 fork()

fork在英文中是“分叉”的意思。为什么取这个名字呢?由于一个进程在运转中,假设运用了fork,就发生了另一个进程,于是进程就“分叉”了,所以这个名字取得很笼统。下面就看看如何详细运用fork,这段顺序演示了运用fork的基本框架

代码如下:

void main()

{

int i;

if ( fork() == 0 )

{

/* 子进程顺序 */

for ( i = 1; i <1000; i ++ )

printf(“This is child process ”);

}

else

{

/* 父进程顺序*/

for ( i = 1; i <1000; i ++ )

printf(“This is process process ”);

}

}

顺序运转后,你就能看到屏幕上交替出现子进程与父进程各打印出的一千条信息了。假设顺序还在运转中,你用ps命令就能看到系统中有两个它在运转了。

那么调用这个fork函数时发作了什么呢?fork函数启动一个新的进程,前面我们说过,这个进程简直是当行进程的一个拷贝:子进程和父进程运用相反的代码段;子进程复制父进程的堆栈段和数据段。这样,父进程的一切数据都可以留给子进程,但是,子进程一旦末尾运转,虽然它承袭了父进程的一切数据,但实践上数据却曾经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。它们再要交互信息时,只要经过进程间通讯来完成,这将是我们下面的内容。既然它们如此相象,系统如何来区分它们呢?这是由函数的前往值来决议的。关于父进程, fork函数前往了子顺序的进程号,而关于子顺序,fork函数则前往零。在操作系统中,我们用ps函数就可以看到不同的进程号,对父进程而言,它的进程号是由比它更低层的系统调用赋予的,而关于子进程而言,它的进程号即是fork函数对父进程的前往值。在顺序设计中,父进程和子进程都要调用函数fork()下面的代码,而我们就是应用fork()函数对父子进程的不同前往值用if…else…语句来完成让父子进程完成不同的功用,正如我们下面举的例子一样。我们看到,下面例子执行时两条信息是交互无规则的打印出来的,这是父子进程独立执行的结果,虽然我们的代码似乎和串行的代码没有什么区别。

读者也许会问,假设一个大顺序在运转中,它的数据段和堆栈都很大,一次fork就要复制一次,那么fork的系统开支不是很大吗?其实UNIX自有其处置的方法,大家知道,普通CPU都是以“页”为单位来分配内存空间的,每一个页都是实践物理内存的一个映像,象INTEL的CPU,其一页在通常状况下是 4086字节大小,而无论是数据段还是堆栈段都是由许多“页”构成的,fork函数复制这两个段,只是“逻辑”上的,并非“物理”上的,也就是说,实践执行fork时,物理空间上两个进程的数据段和堆栈段都还是共享着的,当有一个进程写了某个数据时,这时两个进程之间的数据才有了区别,系统就将有区别的“ 页”从物理上也分开。系统在空间上的开支就可以到达最小。下面演示一个足以“搞死”Linux的小顺序,其源代码十分复杂。代码如下:

void main()

{

for( ; ; )

{

fork();

}

}

这个顺序什么也不做,就是死循环地fork,其结果是顺序不时发生进程,而这些进程又不时发生新的进程,很快,系统的进程就满了,系统就被这么多不时发生 的进程“撑死了”。当然只需系统管理员预先给每个用户设置可运转的最大进程数,这个恶意的顺序就完成不了希图了。

2.2.2 exec( )函数族

下面我们来看看一个进程如何来启动另一个顺序的执行。在Linux中要运用exec函数族。系统调用execve()对当行进程停止交流,交流者为一个指定的顺序,其参数包括文件名(filename)、参数列表(argv)以及环境变量(envp)。exec函数族当然不止一个,但它们大致相反,在 Linux中,它们区分是:execl,execlp,execle,execv,execve和execvp,下面我只以execlp为例,其它函数终究与execlp有何区别,请经过manexec命令来了解它们的详细状况。一个进程一旦调用exec类函数,它自身就“死亡”了,系统把代码段交流成新的顺序的代码,废弃原有的数据段和堆栈段,并为新顺序分配新的数据段与堆栈段,独一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过曾经是另一个顺序了。(不过exec类函数中有的还允许承袭环境变量之类的信息。)那么假设我的顺序想启动另一顺序的执行但自己仍想继续运转的话,怎样办呢?那就是结合fork与exec的运用。下面一段代码显示如何启动运转其它顺序:

代码如下:

#include

#include

#include

char command[256];

void main()

{

int rtn; /*子进程的前往数值*/

while(1) {

/* 从终端读取要执行的命令 */

printf( “>” );

fgets( command, 256, stdin );

command[strlen(command)-1] = 0;

if ( fork() == 0 ) {/* 子进程执行此命令 */

execlp( command, NULL );

/* 假设exec函数前往,标明没有正常执行命令,打印错误信息*/

perror( command );

exit( errno );

}

else {/* 父进程, 等候子进程完毕,并打印子进程的前往值 */

wait ( &rtn );

printf( “ child process return %d ”, rtn );

}

}

}

此顺序从终端读入命令并执行之,执行完成后,父进程继续等候从终端读入命令。熟习DOS和WINDOWS系统调用的冤家一定知道DOS/WINDOWS也有exec类函数,其运用方法是相似的,但DOS/WINDOWS还有spawn类函数,由于DOS是单义务的系统,它只能将“父进程”驻留在机器内再执行“子进程”,这就是spawn类的函数。WIN32曾经是多义务的系统了,但还保管了spawn类函数,WIN32中完成spawn函数的方法同前述 UNIX中的方法差不多,开设子进程后父进程等候子进程完毕后才继续运转。UNIX在其一末尾就是多义务的系统,所以从中心角度上讲不需求spawn类函数。在这一节里,我们还要讲讲system()和popen()函数。system()函数先调用fork(),然后再调用exec()来执行用户的登录 shell,经过它来查找可执行文件的命令并剖析参数,最后它么运用wait()函数族之一来等候子进程的完毕。函数popen()和函数 system()相似,不同的是它调用pipe()函数创立一个管道,经过它来完成顺序的规范输入和规范输入。这两个函数是为那些不太勤快的顺序员设计的,在效率和平安方面都有相当的缺陷,在能够的状况下,应该尽量防止。

提供最优质的资源集合

立即查看 了解详情