Linux进程

进程的相关属性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一起使用

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值