进程的相关属性id
进程的相关属性id:进程id,组id,会话id,环境变量,用户id,用户组id
进程的id:
得到调用进程自己的id:pid=getpid();
调用进程的父进程id:pid=getppid();
进程组:
每个进程组都由一个pid_t类型的进程组id表示。如果进程id与其进程组id的值相同,
则被认为是进程组的领导者(当退出时将发生一些特殊的动作)。
得到调用进程的进程组:pid=getpgrp();
更改进程组: int setpgid(pid_t pid,pid_t pgid);
pid表示被设置进程的id,0表示调用进程自身。
如果pid和pgid的值相同,则表示调用进程成为进程组的领导者。
如果pgid为0,则表示pid标识的进程id将作为进程的组id.
会话id:
pid_t getsid(pit_t pid);
pid为0时返回调用进程的会话id,非0时返回pid的会话id.
pid_t setsid(void) ;建立新的进程组和会话
进程的环境:
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
int main(int argc,char **argv,char **envp)
{
while(*envp)
printf("%s\n",*envp++);
}
结果:
jiang@jiang-linux:~/unixprog/2011-3-17$ ./envp.o
ORBIT_SOCKETDIR=/tmp/orbit-jiang
SSH_AGENT_PID=1379
TERM=xterm
SHELL=/bin/bash
XDG_SESSION_COOKIE=c1901b6a420f208f6f4e10a84d7cb74f-1300369896.301113-1811038148
WINDOWID=75497585
GNOME_KEYRING_CONTROL=/tmp/keyring-v5N61Z
GTK_MODULES=canberra-gtk-module
USER=jiang
可以通过全局变量来访问环境变量,(在stdlib.h中定义):
extern char **environ;//声明
#include<stdlib.h>
char *getenv(const char *name);
getenv的参数是希望查找的环境变量名。成功时返回字符串值的指针,失败返回NULL指针。
#include<stdlib.h>
#include<stdio.h>
int main(void)
{
printf("PATH=%s",getenv("PATH"));
return 0;
}
输出:
jiang@jiang-linux:~/unixprog/2011-3-18$ ./env.o
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/gamesjian
一个对应的调用putenv用来改变或者扩充环境变量:
putenv("NEWVARIABLE=value");
执行成功时返回0.
创建进程:fork系统调用
fork系统调用:
#include<sys/types.h>
#include<unistd.h>
pid_t fork(void);
fork系统调用促使内核创建一个新的进程,该进程是调用进程的一个精确的副本。新创建的
进程称为子进程,调用进程称为父进程。在fork调用之后,父进程和它创建的子进程将同时执行,
两个进程在fork调用语句之后恢复执行。进程的pid可以用来区分父进程和子进程,在父进程中pid值被设置为一个非零的正整数,在子进程中设置为0.
//call_fork.c:
#include<stdio.h>
#include<unistd.h>
int main(void)
{
pid_t pid;/* hold process-id in parent*/
printf("Just one process so far\n");
printf("Calling fork....\n");
pid=fork(); /* create new process */
if(pid==0)
{
printf("I'm the child\n");
}
else if(pid>0)
{
printf("I'm the parent,child has pid %d\n",pid);
}
else
{
printf("Fork returned error code,no child\n");
}
return 0;
}
运行结果:
jiang@jiang-linux:~/unixprog/2011-3-14$ ./child_fork.o
I'm the parent,the child1 is 2489
I'm the child1!
I'm the child,my parent is child1
I'm the child1,and I'm the parent,my child is 2490
子进程可以通过调用fork创建自己的子进程。
复杂一点的例子:
//child_fork.c:
#include<stdio.h>
#include<unistd.h>
int main(void)
{
pid_t pid1, pid2,childpid1,childpid2;
pid1=fork();/* create the child1 */
if(pid1>0)
{
printf("I'm the parent,the child1 is %d\n",pid1);
}
else if(pid1==0)
{
printf("I'm the child1!\n");
childpid1=fork();/* create the child's child*/
if(childpid1>0)
{
printf("I'm the child1,and I'm the parent,my child is %d\n",childpid1);
}
else if(childpid1==0)
{
printf("I'm the child,my parent is child1\n");
}
}
/*
pid2=fork();
if(pid2>0)
{
printf("I'm the parent,the child2 is %d\n",pid2);
}
else if(pid2==0)
{
printf("I'm the child2!\n");
childpid2=fork();// create the child's child
if(childpid2>0)
{
printf("I'm the child2,and I'm the parent,my child is %d\n",childpid2);
}
else if(childpid2==0)
{
printf("I'm the child,my parent is child2\n");
}
}
*/
return 0;
}
运行结果:
jiang@jiang-linux:~/unixprog/2011-3-14$ ./child_fork.o
I'm the parent,the child1 is 2831
I'm the child1!
I'm the child,my parent is child1
I'm the child1,and I'm the parent,my child is 2832
创建进程:使用exec运行新程序
#include<unistd.h>
int execl(const char *path,const char *arg0,...,const char *argn,(char *)0);
exec函数族完成一个功能:装载一个新的程序,并将之转换到调用进程的内存空间。如果exec调用
成功,调用程序将被新的程序完全覆盖,并且从新程序的起始处开始运行。结果可以认为是一个新的进程,除了
保持与原调用进程相同的进程id.
必须强调的是exec并不是创建一个新的进程以便与调用进程同时运行,相反,旧的程序将被新程序所覆盖,因此
不像fork调用一样,exec在成功调用之后不会返回。
int execv(const char *path,char* const argv[]);
execv的第一个参数是是包含执行程序路径字符串,第二个是一个字符串数组,char *const argv[];
int execlp(const char *file,const char arg0,...,const char argn,(char*)0);
int execvp(const char *file,char *const argv[]);
execlp与execvp几乎等同于execl与execv。主要差别在于,execlp和execvp的第一个参数是一个简单的文
件名,而不是一个路径名。
//execl_ls.c:
#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>
void main(void)
{
printf("executing ls\n");
execl("/bin/ls","ls","-l",(char*)0);
/* if execl return,the call has failed,so...*/
perror("execl failed to run ls\n");
exit(1);
}
结果:jiang@jiang-linux:~/unixprog/2011-3-15$ ./execl_ls.o
executing ls
总用量 12
-rw-r--r-- 1 jiang jiang 239 2011-03-15 11:49 execl_ls.c
-rwxr-xr-x 1 jiang jiang 7253 2011-03-15 11:49 execl_ls.o
// execv_ls.c :
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
void main(void)
{
char *const av[]={"ls","-l",(char*)0};
execv("/bin/ls",av);
perror("execv failed\n");
exit(1);
}
结果:
jiang@jiang-linux:~/unixprog/2011-3-15$ ./execv_ls.o
总用量 24
-rw-r--r-- 1 jiang jiang 239 2011-03-15 11:49 execl_ls.c
-rwxr-xr-x 1 jiang jiang 7253 2011-03-15 11:49 execl_ls.o
-rw-r--r-- 1 jiang jiang 178 2011-03-15 12:12 execv_ls.c
-rwxr-xr-x 1 jiang jiang 7217 2011-03-15 12:12 execv_ls.o
execvp的简单例子:
myecho.c
//该程序输出接收的命令行参数
//myecho----echo command line arguments
#include<stdio.h>
int main(int argc,char **argv)
{
while(--argc>0)
{
printf("%s ",*++argv);
}
printf("\n");
return 0;
}
下面的程序调用myecho.o:
execvp_myecho.c:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
void main(void)
{
char *const argin[]={"./myecho.o","hello","world",(char*)0};
execvp(argin[0],argin);
exit(1);
}
exec和fork结合起来为程序员提供了一个强有力的工具。在由fork创建的子进程中使用exec时,一个程序
可以在其子进程中运行另一个程序而不会将自己覆盖。
wait系统调用可使一个进程等待它的子进程,直到完成它所做的事。
exec_fork.c:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int fatal(char *s);//用perror来显示一条信息
/* run ls---run ls in a subprocess */
void main(void)
{
pid_t pid;
switch(pid=fork())
{
case -1: //出错
fatal("fork failed");
break;
case 0:
/*child calls exec */
execl("/bin/ls","ls","-l",(char*)0);
fatal("exec failed");
break;
default:
/* parent uses wait to suspend execution
* until child finishes
*/
wait((int*)0);
printf("is completed\n");
break;
}
exit(0);
}
int fatal(char *s)
{
perror(s);
exit(1);
}
运行结果:
jiang@jiang-linux:~/unixprog/2011-3-15$ ./exec_fork.o
总用量 60
-rw-r--r-- 1 jiang jiang 536 2011-03-15 16:10 exec_fork.c
-rwxr-xr-x 1 jiang jiang 7348 2011-03-15 16:10 exec_fork.o
-rw-r--r-- 1 jiang jiang 239 2011-03-15 11:49 execl_ls.c
-rwxr-xr-x 1 jiang jiang 7253 2011-03-15 11:49 execl_ls.o
-rw-r--r-- 1 jiang jiang 178 2011-03-15 12:12 execv_ls.c
-rwxr-xr-x 1 jiang jiang 7217 2011-03-15 12:12 execv_ls.o
-rw-r--r-- 1 jiang jiang 172 2011-03-15 12:36 execvp_myecho.c
-rwxr-xr-x 1 jiang jiang 7185 2011-03-15 12:36 execvp_myecho.o
-rw-r--r-- 1 jiang jiang 259 2011-03-15 12:27 myecho.c
-rwxr-xr-x 1 jiang jiang 7181 2011-03-15 12:33 myecho.o
is completed
使用exec和fork:实现shell命令在程序内部运行
使用exec和fork实现shell命令在程序内部运行:(非常近似库函数system)
在调用shell时,其中的参数-c用来告诉它从下一个字符串参数而非标准输入中获取命令。
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
/* doconmand---run shell command */
int docommand(char *command)
{
pid_t pid;
if((pid=fork())<0)
{
return (-1);
}
if(pid==0) //child
{
execl("/bin/sh","sh","-c",command,(char*)0);
perror("execl");
exit(1);
}
/* code for parent */
/* wait until child exits */
wait((int*)0);
return 0;
}
int main(int argc,char **argv)
{
int docommand(char *command);
if(argc!=2)
{
printf("only accept a argument!\n");
return (-1);
}
if(docommand(argv[1])!=0)
{
printf("run shell command failed\n");
return (-1);
}
return 0;
}
结果:
jiang@jiang-linux:~/unixprog/2011-3-15$ ./execl_shell.o ps
PID TTY TIME CMD
1752 pts/1 00:00:00 bash
2165 pts/1 00:00:00 execl_shell.o
2166 pts/1 00:00:00 sh
2167 pts/1 00:00:00 ps
同步进程:wait系统调用
wait系统调用:
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int *status);
当子进程运行时,wait会暂时将调用进程挂起。一旦子进程结束了,等待的父进程就可以继续执行。
如果多于一个子进程正在运行,wait将在父进程的任意一个子进程退出时返回。wait的返回值一般是退出的
子进程的进程id。如果wait返回(pid_t)-1,就意味着没有子进程退出,并且在此情况下errno将包含一个错误代码
ECHILD。为了能够逐个判定子进程是否退出,父进程可以进入一个循环,来等待它的每一个子进程。
wait需要传入一个参数status,一个整型指针。如果指针的值为null,则这个参数将被简单地忽略掉。
如果wait被传入一个有效的指针,当wait返回时status将包含有用的状态信息,通常该信息就是子进程调用
exit时传入的退出状态信息。
wait.c:
/* wait---how to get hold of a child's exit status */
#include<stdio.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
int fatal(char *s);
int main(void)
{
pid_t pid;
int status,exit_status;
if((pid=fork())<0)
{
fatal("fork failed");
}
if(pid==0) //child
{
sleep(4);
exit(5);
}
if((pid=wait(&status))==-1)
{
perror("wait failed");
exit(2);
}
/*test to see how the child dead */
if(WIFEXITED(status))
{
exit_status=WEXITSTATUS(status);
printf("Exit status from %d was %d\n",pid,exit_status);
}
exit(0);
}
int fatal(char *s)
{
perror(s);
exit(-1);
}
运行结果:
jiang@jiang-linux:~/unixprog/2011-3-17$ ./wait.o
Exit status from 2137 was 5
通过exit返回给父进程的状态值保存在整型变量status的高8位中,宏WIFEXITED(在<sys/wait.h>中定义)
返回status高8位的值。如果WIFEXITED返回为0,则表明子进程运行轨迹被其他进程打断。
同步进程:waitpid系统调用
#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid,int *status,int options);
pid参数为-1表示对任意一个子进程都感兴趣,如果pid大于0,则父进程将等待进程id为pid的子进程。
第二个参数status保存waitpid返回时子进程的状态。最后一个参数定义为WNOHANG时,表示waitpid进入
一个循环以检测一个状态,而不会在子进程运行时阻塞调用,子进程未终止时返回0
waitpid.c:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
int fatal(char *s);
int main(void)
{
pid_t pid;
int status,exit_status;
if((pid=fork())<0)
{
fatal("fork failed");
}
if(pid==0)
{
printf("Child %d sleeping....\n",getpid());
sleep(4);
exit(5);
}
/* WNOHANG return immediately if no child has exited.
if WNOHANG was specified and one or more child(ren) specified by pid exist, but have not yet changed state, then 0 is returned.
On error, -1 is returned.*/
while(waitpid(pid,&status,WNOHANG)==0)//表示子进程未终止
{
printf("Still waiting...\n");
sleep(1);
}
if(WIFEXITED(status))
{
exit_status=WEXITSTATUS(status);
printf("Exit status from %d was %d\n",pid,exit_status);
}
exit(0);
}
int fatal(char *s)
{
perror(s);
exit(-1);
}
结果:
jiang@jiang-linux:~/unixprog/2011-3-17$ ./waitpid.o
Still waiting...
Child 3582 sleeping....
Still waiting...
Still waiting...
Still waiting...
Exit status from 3582 was 5