说到进程,首先要明确的一个概念就是什么是进程,进程是“a program in execution”。一个进程由如下元素组成:
–程序的上下文(context),它是程序当前执行的状态
–程序的当前执行目录
–程序访问的文件和目录
–程序的信任状态或者说访问权限,比如它的文件模式和所有权
–内存和其他分配给进程的系统资源
本文讨论创建进程
1、 system库函数
在头文件#include<stdlib.h>中包含
函数原型: int system(const char *command);
功能描述: system()通过调用/bin/sh –c command来执行具体的command命令,在command完成后返回。在command执行期间,SIGCHLD信号被阻塞,SIGINT和SIGQUIT将被忽略。
返回值: 如果没有找到/bin/sh,system返回127;
如果出现其他错误则返回-1;
如果执行成功则返回command的代码。
但是如果command为NULL,system返回一个非0值,否则返回0。
示例:\
#include<stdlib.h>
#include<stdio.h>
int main()
{
printf("Running ps with system\n");
system("ps -ax");
//ps命令完成后从system调用中返回,继续执行下一个语句,Done出现在末尾。若改为system("ps -ax &");后台执行ps命令,ps程序一启动shell就返回了。故Done会出现在中间。
printf("Done.\n");
exit(0);
}
2、 fork系统调用
fork调用创建一个新的进程。新的进程或者说子进程是调用进程的或者说父进程的副本。
Fork的语法是
#include<unistd.h>
pid_t fork(void);
如果fork执行成功,就向父进程返回子进程的PID,并向子进程返回0。这就一起这即使你只调用fork一次,他也会返回两次。
Fork创建的新进程是和父进程(除了PID和PPID)一样的副本,包括真实和有效的UID和GID、进程组合会话ID、环境、资源限制、打开的文件以及共享内存段。
父进程和子进程之间有一点区别。子进程没有继承父进程的超市设置(使用alarm调用
)父进程创建的文件锁,或者未决信号。要理解的关键概念是fork创建的新进程是父进程的一个准确副本。
2、fork系统调用
fork调用创建一个新的进程。新的进程或者说子进程是调用进程的或者说父进程的副本。
Fork的语法是
#include<unistd.h>
pid_t fork(void);
如果fork执行成功,就向父进程返回子进程的PID,并向子进程返回0。这就一起这即使你只调用fork一次,他也会返回两次。
Fork创建的新进程是和父进程(除了PID和PPID)一样的副本,包括真实和有效的UID和GID、进程组合会话ID、环境、资源限制、打开的文件以及共享内存段。
父进程和子进程之间有一点区别。子进程没有继承父进程的超时设置(使用alarm调用)父进程创建的文件锁,或者未决信号。要理解的关键概念是fork创建的新进程是父进程的一个准确副本。
示例:
- <span style="font-size: 14px;">#include<unistd.h>
- #include<stdio.h>
- #include<stdlib.h>
- #include<string.h>
- int main(void)
- {
- pid_t child;
- if((child = fork()) == -1)
- {
- perror("fork");
- exit(EXIT_FAILURE);
- }
- else if(child == 0) //子进程中
- {
- puts("in child");
- printf("\tchild pid = %d\n",getpid());
- printf("\tchild ppid = %d\n",getppid());
- exit(EXIT_SUCCESS);
- }
- else
- {
- puts("in parent");
- printf("\tparent pid = %d\n",getpid());
- printf("\tparent ppid = %d\n",getppid());
- }
- exit(EXIT_SUCCESS);
- }
- </span>
<span style="font-size: 14px;">#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
pid_t child;
if((child = fork()) == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
else if(child == 0) //子进程中
{
puts("in child");
printf("\tchild pid = %d\n",getpid());
printf("\tchild ppid = %d\n",getppid());
exit(EXIT_SUCCESS);
}
else
{
puts("in parent");
printf("\tparent pid = %d\n",getpid());
printf("\tparent ppid = %d\n",getppid());
}
exit(EXIT_SUCCESS);
}
</span>
3、 exec函数族
与fork函数一样,exec也在<unistd.h>中声明。它的原型为:
int execl(const char *path, const char*arg, ...(char *) 0);//以0结尾
int execlp(const char *file, const char*arg, ...(char *) 0);
int execle(const char *path, const char*arg , ...,(char *) 0, char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
exec用被执行的程序完全替换了调用进程的映像。Fork创建了一个新进程就产生了一个新的PID,exec启动一个新程序,替换原有进程。因此被执行的进程的PID不会改变。
例如:
int execve(const char *path, char *constargv[], char *const envp[]);
接收三个参数:
path是要执行的二进制文件或脚本的完整路径。
argv是要传递给程序的完整参数列表,包括argv[0],它一般是执行程序的名字,
envp是指向用于执行execed程序的专门环境的指针。
这几个函数可以简单讨论如下:
名字中含有l的函数:希望接受以逗号分隔的参数列表,列表以NULL指针作为结束标志,这些参数将传递给被执行的程序。
名字中包v的函数:则接受一个向量,也就是以空结尾的字符串的指针数组。这个数组必须以一个NULL指针作为结束标志。
不过,需要注意的是,有时候可能那个NULL,需要写成(char *)0。
- <span style="font-size: 14px;">//一个创建num个进程的示例:
- //其中batchscript是已经写好的shell脚本文件。
- void createsubprocess(int num)
- {
- int i;
- int child;
- int pid[num];
- for(i=0;i<num;i++)
- {
- if((child = fork()) == -1)
- {
- perror("fork");
- exit(EXIT_FAILURE);
- }
- else if(child==0) //子进程运行
- {
- pid[i]=getpid();
- if(execl("/usr/audio/./batchscript","./batchscript",(char *)0) == -1 )
- {
- perror("execl");
- exit(EXIT_FAILURE);
- }
- }
- else
- {
- }
- }
- for(i=0;i<num;i++)
- {
- waitpid(pid[i],NULL,0);
- }
- }
- </span>
<span style="font-size: 14px;">//一个创建num个进程的示例:
//其中batchscript是已经写好的shell脚本文件。
void createsubprocess(int num)
{
int i;
int child;
int pid[num];
for(i=0;i<num;i++)
{
if((child = fork()) == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
else if(child==0) //子进程运行
{
pid[i]=getpid();
if(execl("/usr/audio/./batchscript","./batchscript",(char *)0) == -1 )
{
perror("execl");
exit(EXIT_FAILURE);
}
}
else
{
}
}
for(i=0;i<num;i++)
{
waitpid(pid[i],NULL,0);
}
}
</span>
实现了多进程并发。