linux系统编程:进程原语

                        进程原语

1. 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
2. 进程环境
在libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明。用以下代码可以查看当前进程的所有环境变量的信息。

#include  
int main(void)
{
    extern char **environ;
    int i;
    for(i = 0; environ[i] != NULL;  i++)
    printf("%s\n", environ[i]);
    return 0;
}

运行结果用键值对的形式展示环境变量的信息。几个常见的环境变量解释:
PATH:可执行文件的搜索路径。
SHELL:当前使用的shell。
HOME:当前用户的主目录路径。
3. 进程状态
4种主要的进程状态:运行、就绪、挂起、终止。
4. 进程原语
在liunx中使用函数fork创建新的进程。

#include 
pid_t fork(void);

函数特点:调用一次,返回两次。
在父进程中,返回创建的子进程的pid;在子进程中返回0;出错,返回-1。
一个创建子进程的实例:

#include 
#include 
#include 
#include 
void sys_err(char *s)
{
    perror(s);
    exit(1);
}
int main(void)
{
    pid_t pid;
    pid = fork();
    if (pid < 0)
        sys_err("fork");
    else if (pid > 0)
    {
        /* parent process */
        printf("I am parent,my pid is %d, my parent pid is %d\n", getpid(), getppid());
        sleep(1);   //休眠1秒,防止父进程过早退出
    }
    else
    {
        /* child process */
        printf("I am child,my pid is %d, my parent pid is %d\n", getpid(), getppid());
    }
    return 0;
}
//I am child, my pid is 15057, my parent pid is 15056
//I am parent, my pid is 15056, my parent pid is 5292
#include 
#include    //定义了pid_t、uid_t、gid_t
pid_t getpid(void);   //获取当前进程的pid
pid_t getppid(void);  //获取当前进程父进程的pid
uid_t getuid(void);   //返回实际用户id
uid_t geteuid(void);  //返回有效用户id
gid_t getgid(void);   //返回实际用户组id
gid_t getegid(void);  //返回有效用户组id

所有id都是正数。
父进程和子进程的关系:
1.子进程复制了父进程的PCB(除了pid)和代码段以及数据区。
2.用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
5. exec族

#include 
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., 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[]);

只需弄懂了execl的使用,其它的举一反三了:path指出了新可执行程序的路径,后面的arg,即是提供的参数。
使用execl函数更改程序的执行:

//show.c
#include 
int main(int argc, char **argv)
{
    int i = 0;
    while(i < argc)
        printf("%s\n", argv[i++]);
    return 0;
}
//app.c
#include 
#include 
#include 
int main(int argc, char **argv)
{
    if(argc < 2)
    {
        fprintf(stderr, "usage:app newapp ...");
        exit(1);
    }
    printf("zhangxiang\n");
    //$ argv[1] zx [email protected]
    execl(argv[1], "zx", "[email protected]", NULL);  //NULL用于指明参数列表的结束
    printf("David\n");
    return 0;
}
$ gcc show.c -o show
$ gcc app.c -o app
$ app show
zhangxiang
zx
zhangxiangDavid@126.com

执行printf(“zhangxiang\n”);了后,程序的代码段被替换,所以原程序的printf(“David\n”);不会被执行。

l 命令行参数列表
p 搜素file时使用path变量
v 使用命令行参数数组
e 使用环境变量数组,不使用进程原有的环境变量,设置新加载程序运行的环境变量
这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回,如果调用出错则返回-1,所以exec函数只有出错的返回值而没有成功的返回值。
6. wait()、waitpid()
僵尸进程::子进程退出,父进程没有回收子进程资源(PCB),则子进程变成僵尸进程。
孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为1号进程init进程,称为init进程领养孤儿进程。
子进程结束后,PCB仍然滞留在内存。父进程可以通过子进程的PCB来获知子进程的退出状态:正常退出时的退出码、不正常退出时,是被哪个信号终止的。

#include 
#include 
pid_t wait(int *status);

函数说明:
参数status为传出参数,用于记录退出状态。
当没有子进程退出时,wait调用会阻塞当前进程。
成功,返回子进程的pid;
失败,返回-1;

#include 
#include 
#include 
#include 
#include 
int main(void)
{
    pid_t pid, wpid;
    pid = fork();
    if(0 == pid)
    {
        printf("in child\n");
        sleep(2);
        printf("child exit\n");
    }
    else if(pid > 0)
    {
        while(1)
        {
            wpid = wait(NULL);
            printf("in parent %d\n", wpid);
            sleep(1);
        }
    }
    else
    {
        perror("fork");
        exit(1);
    }
    return 0;
}
//in child
//child exit
//in parent 27909
//in parent -1
//in parent -1
//^c

wait()会使父进程阻塞,为了不阻塞,需使用waitpid()

#include 
#include 
pid_t waitpid(pid_t pid, int *status, int options);

函数说明:
pid指明了需回收哪个子进程的PCB;
通过指定options的值,更改函数运行状态。(特别地,指定WNOHANG,将不会阻塞)。
指定WNOHANG,非阻塞后。若没有进程退出,返回0,其它同wait。

#include 
#include 
#include 
#include 
#include 
int main(void)
{
    pid_t pid, wpid;
    pid = fork();
    if(0 == pid)
    {
        printf("in child\n");
        sleep(2);
        printf("child exit\n");
    }
    else if(pid > 0)
    {
        while(1)
        {
            wpid = waitpid(0, NULL, WNOHANG);
            printf("in parent %d\n", wpid);
            sleep(1);
        }
    }
    else
    {
        perror("fork");
        exit(1);
    }
    return 0;
}
//in parent 0
//in child
//in parent 0
//child exit
//in parent 28700
//in parent -1
//in parent -1
//^c

CCPP Blog 目录

你可能感兴趣的:(linux系统编程,linux,c,C++,进程)