`
forfuture1978
  • 浏览: 412951 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

高级Linux程序设计第三章:进程

阅读更多

 

高级Linux程序设计第一章:入门

http://forfuture1978.iteye.com/blog/649981

高级Linux程序设计第二章:编写良好的Linux软件

http://forfuture1978.iteye.com/blog/652338

 

 

  • 每个进程都有一个唯一的进程号。

  • 每个进程都有一个父进程。

  • 系统中的进程以树的形式组织,init进程(进程号为1)作为根。

    • 进程0是调度进程,没有程序与之对应,是内核的一部分。

    • 进程1是init进程,是在系统启动的阶段由内核启动的,对应/sbin/init程序,是普通的用户进程。

  • 程序中可以通过getpid()得到进程号,通过getppid()得到父进程的进程号。

 

#include <stdio.h>

#include <unistd.h>

int main ()

{

    printf (“The process ID is %d\n”, (int) getpid ());

    printf (“The parent process ID is %d\n”, (int) getppid ());

    return 0;

}

  • 通过ps命令可以得到系统中运行的所有进程。

  • 通过kill命令可以杀掉某个进程。

1、创建进程

1.1、system函数

  • system函数提供了一种在程序中运行一个命令的简单方法。

 

#include <stdlib.h>

int main ()

{

    int return_value;

    return_value = system (“ls -l /”);

    return return_value;

}

1.2、fork及exec函数

  • 当程序调用fork的时候,则一个完全复制的子程序被创建。

  • 父进程将从fork被调用的地方继续执行下去。

  • 子进程也是从相同的地方运行下去。

  • 父进程中fork函数的返回值是子进程的进程号。

  • 子进程中fork函数的返回值是零。

#include <stdio.h>

#include <sys/types.h>

#include <unistd.h>

int main ()

{

    pid_t child_pid;

    printf (“the main program process ID is %d\n”, (int) getpid ());

    child_pid = fork ();

    if (child_pid != 0) {

        printf (“this is the parent process, with id %d\n”, (int) getpid ());

        printf (“the child’s process ID is %d\n”, (int) child_pid);

    }

    else

        printf (“this is the child process, with id %d\n”, (int) getpid ());

    return 0;

}

  • exec函数将当前运行的进程替换为另一个程序。

  • exec函数是一组函数:

    • 包含p的函数(execvp, execlp)接收的参数是程序名。

    • 不包含p的函数接收的参数是程序的全路径。

    • 包含v的函数(execv, execvp, execve)以数组的形式接收参数列表。

    • 包含l的函数(execl, execlp, execle)以列举的形式接收参数列表。

    • 包含e的函数(execve, execle)以数组的形式接收环境变量。

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <unistd.h>

/* Spawn a child process running a new program. PROGRAM is the name of the program to run; the path will be searched for this program. ARG_LIST is a NULL-terminated list of character strings to be passed as the program’s argument list. Returns the process ID of the spawned process. */

int spawn (char* program, char** arg_list)

{

    pid_t child_pid;

    /* Duplicate this process. */

    child_pid = fork ();

    if (child_pid != 0)

    /* This is the parent process. */

        return child_pid;

    else {

        /* Now execute PROGRAM, searching for it in the path. */

        execvp (program, arg_list);

        /* The execvp function returns only if an error occurs. */

        fprintf (stderr, “an error occurred in execvp\n”);

        abort ();

    }

}

int main ()

{

    /* The argument list to pass to the “ls” command. */

    char* arg_list[] = {

        “ls”, /* argv[0], the name of the program. */

        “-l”,

        “/”,

        NULL /* The argument list must end with a NULL. */

    };

    /* Spawn a child process running the “ls” command. Ignore the returned child process ID. */

    spawn (“ls”, arg_list);

    printf (“done with main program\n”);

    return 0;

}

 

2、信号

  • 信号是发送给进程的特殊信息。

  • 当一个进程接收到一个信号的时候,它会立即处理此信号,并不等待完成当前的函数调用甚至当前一行代码。

  • 系统会在特殊情况下向进程发送信号:

    • SIGBUS:总线错误

    • SIGSEGV:段违规

    • SIGFPE:浮点数异常

  • 一个进程可以向另一个进程发送信号。

  • 可以发送SIGTERM和SIGKILL信号来结束一个进程。

  • 信号可以用来向一个进程发送命令。有两种用户自定义信号:SIGUSER1和SIGUSR2

  • sigaction函数设定信号处理方式

    • SIG_DFL表示使用默认的信号处理方式。

    • SIG_IGN表示此信号可以被忽略。

    • 第二个参数是sigaction结构体,其包括一个信号处理函数。

  • 由于信号处理是异步的,因而在信号处理函数中不要调用I/O操作,也不要调用库或者系统的函数。

  • 信号处理函数中应该尽量处理最少的东西。

  • 信号处理函数也可能被另一个信号中断。

  • 如果在信号处理函数中期望对一个全局变量进行操作,此变量应该是sig_atomic_t类型。

#include <stdio.h>

#include <signal.h>

#include <string.h>

#include <sys/types.h>

#include <unistd.h>

sig_atomic_t sigusr1_count = 0;

void handler(int signal_number)

{

++sigusr1_count;

}

int main(int argc, char* argv[])

{

    printf("the process ID is %d\n", (int)getpid());

    struct sigaction sa;

    memset(&sa, 0, sizeof(sa));

    sa.sa_handler = &handler;

    sigaction(SIGUSR1, &sa, NULL);

    int i = 0;

    while(i < 100)

    {

        sleep(1);

        i++;

    }

    printf("SIGUSR was raised %d times\n", sigusr1_count);

    return 0;

}

编译上述代码为程序sigusr1

gcc -o sigusr1 sigusr1.c

运行程序

[liuchao@localhost Signal]$ ./sigusr1

the process ID is 3401

在另一个终端,用ps命令得到sigusr1的进程号

[liuchao@localhost ~]$ ps -a

PID TTY TIME CMD

3401 pts/1 00:00:00 sigusr1

3403 pts/3 00:00:00 ps

向此进程号发送多个sigusr1信号

[liuchao@localhost ~]$ kill -s SIGUSR1 3401

[liuchao@localhost ~]$ kill -s SIGUSR1 3401

[liuchao@localhost ~]$ kill -s SIGUSR1 3401

[liuchao@localhost ~]$ kill -s SIGUSR1 3401

[liuchao@localhost ~]$ kill -s SIGUSR1 3401

当进程结束后

[liuchao@localhost Signal]$ ./sigusr1

the process ID is 3401

SIGUSR was raised 5 times

 

3、结束进程

  • 一个进程可以有两种方式结束:

    • 进程本身调用exit函数,或者其main函数结束。

    • 进程接收到信号后异常结束。

      • ctrl+c发送SIGINT信号

      • kill命令发送SIGTERM信号

      • abort函数发送SIGABRT信号

      • SIGKILL函数会立即结束一个进程,此信号不能被阻止,被程序自己处理。

  • 所有这些信号都可以用kill命令发送

 

% kill -KILL pid
  • 用kill函数可以在程序中向一个进程发送信号。

kill (child_pid, SIGTERM);
  • 有关wait函数:

    • wait函数阻止当前的进程,直到其中一个子进程结束。

    • waitpid函数等待一个指定的子进程结束。

    • wait3函数等待子进程结束并返回子进程的各种资源使用的统计。

    • wait4函数等待特定的子进程结束并返回子进程的各种资源使用的统计。

int main ()

{

    int child_status;

    /* The argument list to pass to the “ls” command. */

    char* arg_list[] = {

        “ls”, /* argv[0], the name of the program. */

        “-l”,

        “/”,

        NULL /* The argument list must end with a NULL. */

    };

    /* Spawn a child process running the “ls” command. Ignore the returned child process ID. */

    spawn (“ls”, arg_list);

    /* Wait for the child process to complete. */

    wait (&child_status);

    if (WIFEXITED (child_status))

        printf (“the child process exited normally, with exit code %d\n”, WEXITSTATUS (child_status));

    else

        printf (“the child process exited abnormally\n”);

    return 0;

}

  • 所谓僵死的进程指的是一个进程结束了但资源尚未被回收。

  • 父进程有责任在子进程结束的时候用wait函数回收子进程的资源。

  • 在子进程尚未被父进程回收的时候,其在系统中作为僵死进程存在。

#include <stdlib.h>

#include <sys/types.h>

#include <unistd.h>

int main ()

{

    pid_t child_pid;

    /* Create a child process. */

    child_pid = fork ();

    if (child_pid > 0) {

        /* This is the parent process. Sleep for a minute. */

       sleep (60);

    }

    else {

        /* This is the child process. Exit immediately. */

        exit (0);

    }

    return 0;

}

% ps -e -o pid,ppid,stat,cmd

3824 2888 S+ ./zombie

3825 3824 Z+ [zombie] <defunct>

  • 当一个程序结束的时候,其所有的子进程都被一个特殊的进程(init进程)继承。init进程负责回收所有它继承过来的僵死的子进程。

  • 当一个子进程结束的时候,将对其父进程发送SIGCHID信号。

  • 一个进程可以通过处理SIGCHID信号来回收子进程。

#include <signal.h>

#include <string.h>

#include <sys/types.h>

#include <sys/wait.h>

sig_atomic_t child_exit_status;

void clean_up_child_process (int signal_number)

{

    /* Clean up the child process. */

    int status;

    wait (&status);

    /* Store its exit status in a global variable. */

    child_exit_status = status;

}

int main ()

{

    /* Handle SIGCHLD by calling clean_up_child_process. */

    struct sigaction sigchld_action;

    memset (&sigchld_action, 0, sizeof (sigchld_action));

    sigchld_action.sa_handler = &clean_up_child_process;

    sigaction (SIGCHLD, &sigchld_action, NULL);

    /* Now do things, including forking a child process. */

    /* ... */

    return 0;

}


 

2
2
分享到:
评论

相关推荐

    Linux程序设计参考书-六部

    World1.1 内核模块的Makefiles文件1.2 多重文件内核模块第2章字符设备...程序第12章对称多处理第13章常见错误附录A 2.0和2.2之间的差异附录B 其他资源附录C 给出你的评价第三部Linux程序员指南第1章Linux操作系统第2...

    Linux程序设计中文第4版.part3

     1.2 Linux程序设计  1. 2.1 Linux程序  1. 2.2 文本编辑器  1. 2.3 C语言编译器  1. 2.4 开发系统导引  1.3 获得帮助  1.4 小结 第2章 shell程序设计  2.1 为什么使用shell编程  ...

    Linux程序设计中文第4版.part2

     1.2 Linux程序设计  1. 2.1 Linux程序  1. 2.2 文本编辑器  1. 2.3 C语言编译器  1. 2.4 开发系统导引  1.3 获得帮助  1.4 小结 第2章 shell程序设计  2.1 为什么使用shell编程  ...

    Linux程序设计中文第4版.part1

     1.2 Linux程序设计  1. 2.1 Linux程序  1. 2.2 文本编辑器  1. 2.3 C语言编译器  1. 2.4 开发系统导引  1.3 获得帮助  1.4 小结 第2章 shell程序设计  2.1 为什么使用shell编程  2.2 一点...

    linux程序设计(第三版)

    本书作者具有28年以上的大学教学经验,这些年来,曾讲授了有关LINUXUNIX平台的广泛课程,包括程序设计、数据结构、操作系统和软件工程,但并未找到一本适合于当前使用的、系统描述LINUX和UNIX编程工具和实用程序...

    Linux程序设计 第4版.haozip01

    Linux程序设计 分卷文件共有以下2个: Linux程序设计 第4版.haozip01.zip Linux程序设计 第4版.haozip02.zip 基本信息 原书名: Beginning Linux Programming 原出版社: Wrox 作者: (英)Neil Matthew Richard ...

    linux高级程序设计源码(第三版 杨宗德著)

    非常适合学习linux操作系统编程的人员使用,例程丰富,涵盖文件操作,进程管理,线程管理,串口编程,进程间通信,异步操作

    Linux C程序设计大全

    第3篇 Linux进程操作 第10章 进程环境 第11章 进程控制 第12章 时间和日历历程 第13章 信号及信号处理 第14章 进程间通信 第15章 线程 第4篇 Linux文件操作 第17章 文件I/O 第18章 文件管理 第19章 目录操作 第20章 ...

    Linux程序设计 第4版.haozip02

    Linux程序设计 分卷文件共有以下2个: Linux程序设计 第4版.haozip01.zip Linux程序设计 第4版.haozip02.zip 基本信息 原书名: Beginning Linux Programming 原出版社: Wrox 作者: (英)Neil Matthew Richard ...

    LINUX高级程序设计(中文第二版)第三章 LINUX进程存储管理

    俺花了N个大洋买来的,现在免费提供给大家

    嵌入式Linux程序设计案例与实验教程(配套光盘)第一部分

    第3章 嵌入式Linux内核、引导系统和文件系统36 3.1 Linux内核定制、裁剪和添加36 3.1.1 概述36 3.1.2 内核目录简介37 3.1.3 配置文件和配置工具37 3.1.4 内核的编译命令39 实验3.1 Linux内核裁剪与编译40 3.2...

    嵌入式Linux程序设计案例与实验教程(配套光盘)第三部分

    第3章 嵌入式Linux内核、引导系统和文件系统36 3.1 Linux内核定制、裁剪和添加36 3.1.1 概述36 3.1.2 内核目录简介37 3.1.3 配置文件和配置工具37 3.1.4 内核的编译命令39 实验3.1 Linux内核裁剪与编译40 3.2...

    嵌入式Linux程序设计案例与实验教程(配套光盘)第二部分

    第3章 嵌入式Linux内核、引导系统和文件系统36 3.1 Linux内核定制、裁剪和添加36 3.1.1 概述36 3.1.2 内核目录简介37 3.1.3 配置文件和配置工具37 3.1.4 内核的编译命令39 实验3.1 Linux内核裁剪与编译40 3.2...

    Linux进程编程介绍

    第三章:介绍一些有关进程的特殊操作。有了这些操作,就使得进程的编程更加完善,能编制更为实用的程序。主要的内容有得到关于进程的各种ID、对进程的设置用户ID、改变进程的工作目录、改变进程的根、改变进程的...

    Linux高性能服务器编程PDF带目录高清版

    第二部分对高性能服务器编程的核心要素进行了全面深入的剖析,包含Linux网络编程API、高级I/O函数、Linux服务器程序规范、高性能服务器程序框架、I/O复用、信号、定时器、高性能I/O框架库Libevent、多进程编程、多...

    嵌入式Linux程序设计案例与实验教程-实例代码

    第3章 嵌入式Linux内核、引导系统和文件系统36 3.1 Linux内核定制、裁剪和添加36 3.1.1 概述36 3.1.2 内核目录简介37 3.1.3 配置文件和配置工具37 3.1.4 内核的编译命令39 实验3.1 Linux内核裁剪与编译...

    Linux的内核与编程

    本书结合源代码分析了Linux操作系统,结合源代码是本书的一个亮点本书共有两个大部分:内核原理和编程方法共19章: 第1章 软件基础 (介绍了内核的数据结构) 第2章 内存管理 (各种管理算法) 第3章 进程第4章 进程间通信...

    linux驱动程序设计入门

    编程又是 Linux 程序设计中比较复杂的部分,究其原因,主要包括如下几个方面: (1)设备驱动属于 Linux 内核的部分,编写 Linux 设备驱动需要有一定的 Linux操作 系统内核基础; (2)编写 Linux 设备驱动需要...

    linux内核设计的艺术

    本书分三部分来讲解Linux 操作系统:第一部分(第1 ~4 章)分析了从开机加电到操作系统启动完成并进入怠速状态的整个过程;...第三部分(第9章)阐述整个Linux 操作系统的设计指导思想,是从微观到宏观的回归。

Global site tag (gtag.js) - Google Analytics