Linux程序设计--11章(进程)

system函数:
 #include <stdlib.h>

 int system(const char *command);
作用:运行以字符串参数到形式传递给它的命令并等待该命令的完成
相当于: sh -c command

局限性:必须用一个shell来启动需要到程序,故效率不高;程序必须等待system函数启动的进程结束之后才能继续,不能立刻执行其他任务

例子:
system1.c
#include <stdlib.h>
#include <stdio.h>

int main()
{
    printf("Running ps with system\n");
    system("ps ax");
    printf("Done.\n");
    exit(0);
}
命令结果完全输出后输出Done.


system2.c
#include <stdlib.h>
#include <stdio.h>

int main()
{
    printf("Running ps with system\n");
    system("ps ax &");
    printf("Done.\n");
    exit(0);
}

命令结果尚未完全输出前输出Done.


exec函数(替换进程映像)

 #include <unistd.h>

       extern char **environ;

       int execl(const char *path, const char *arg, ...
                       /* (char  *) NULL */);
       int execlp(const char *file, const char *arg, ...
                       /* (char  *) NULL */);
       int execle(const char *path, const char *arg, ...
                       /*, (char *) NULL, char * const envp[] */);
       int execv(const char *path, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[],
                       char *const envp[]);


特点:
l参数可变,以(char*)0结尾
v参数以字符串数组传递
p通过搜索PATH变量来查找新程序的可执行文件路径
e可以传递envp字符串数组作为新程序的环境变量
************重要特性******************
exec函数是把所执行进程的程序给替换了
pid,ppid和nice值都未发生变化
发生错误会返回-1

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    printf("Running ps with execlp\n");
    //从PATH中查找ps程序,执行ps ax命令
    execlp("ps", "ps", "ax", 0);
    printf("Done.\n");//这句不会打印
    exit(0);
}


fork
   #include <unistd.h>

   pid_t fork(void);
作用:创建一个子进程,子进程程序代码和父进程相同,在父进程中返回子进程pid,在子进程中返回0
例子:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    pid_t pid;
    char *message;
    int n;

    printf("fork program starting\n");
    //创建子进程并且取得返回值
    pid = fork();
    switch(pid)
    {
    case -1:
        perror("fork failed");
        exit(1);
    case 0://子进程
        message = "This is the child";
        n = 5;
        break;
    default://父进程
        message = "This is the parent";
        n = 3;
        break;
    }

    for(; n > 0; n--) {
        puts(message);
        sleep(1);
    }
    exit(0);
}

wait:
 #include <sys/wait.h>
       
       pid_t wait(int *stat_loc);
       pid_t waitpid(pid_t pid, int *stat_loc, int options);
特点:wait系统调用将暂停父进程直到它的子进程结束为止。
     如果stat_loc不为空,状态信息将被写入它所指向的位置
     waitpid的pid若指定为-1则将返回任一子进程的信息,指定某一子进程pid可等待特定子进程结束
     选项options可以改变waitpid的行为:WNOHANG防止waitpid调用将调用者的执行挂起
如果想让父进程周期性的检查某个特定的子进程是否已终止可用如下方式:
waitpid(child_pid,(int *)0,WNOHANG);
例子:


#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    pid_t pid;
    char *message;
    int n;
    int exit_code;

    printf("fork program starting\n");
    pid = fork();
    switch(pid)
    {
    case -1:
        exit(1);
    case 0:
        message = "This is the child";
        n = 5;
        exit_code = 37;//子进程退出码
        break;
    default:
        message = "This is the parent";
        n = 3;
        exit_code = 0;
        break;
    }

    for(; n > 0; n--) {
        puts(message);
        sleep(1);
    }

/*  This section of the program waits for the child process to finish.  */

    if(pid) {//父进程
        int stat_val;
        pid_t child_pid;
    //等待子进程结束
        child_pid = wait(&stat_val);

        printf("Child has finished: PID = %d\n", child_pid);
        if(WIFEXITED(stat_val))
            printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
        else
            printf("Child terminated abnormally\n");
    }
    exit (exit_code);
}
输入输出重定向:
例子:


#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

int main()
{
    int ch;
    while((ch = getchar()) != EOF) {
        putchar(toupper(ch));
    }
    exit(0);
}

 ./upper < file.txt
THIS IS THE FILE, FILE.TXT; IT IS ALL LOWER CASE.


用exec调用upper函数


/*  This code, useupper.c, accepts a file name as an argument
    and will respond with an error if called incorrectly.  */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    char *filename;

    if(argc != 2) {
        fprintf(stderr, "usage: useupper file\n");
        exit(1);
    }

    filename = argv[1];

/*  That done, we reopen the standard input, again checking for any errors as we do so,
    and then use execl to call upper.  */

    if(!freopen(filename, "r", stdin)) {//重定向标准输入为filename指定的文件
        fprintf(stderr, "could not redirect stdin to file %s\n", filename);
        exit(2);
    }

    execl("./upper", "upper", 0);

/*  Don't forget that execl replaces the current process;
    provided there is no error, the remaining lines are not executed.  */

    perror("could not exec ./upper");
    exit(3);
}
重定向后原进程中打开的文件描述符仍然保持打开;getchar从标准输入读数据,而标准输入又被重定向到file.txt,所以读到的是file.txt里的内容


信号:
signal
  #include <signal.h>

   void (*signal(int sig, void (*func)(int)))(int);
例子:

/*  We'll start by writing the function which reacts to the signal
    which is passed in the parameter sig.
    This is the function we will arrange to be called when a signal occurs.
    We print a message, then reset the signal handling for SIGINT
    (by default generated by pressing CTRL-C) back to the default behavior.
    Let's call this function ouch.  */

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void ouch(int sig)
{
    printf("OUCH! - I got signal %d\n", sig);
    //把信号处理恢复为默认
    (void) signal(SIGINT, SIG_DFL);
}

/*  The main function has to intercept the SIGINT signal generated when we type Ctrl-C .
    For the rest of the time, it just sits in an infinite loop,
    printing a message once a second.  */

int main()
{
    //注册信号处理函数    
    (void) signal(SIGINT, ouch);

    while(1) {
        printf("Hello World!\n");
        sleep(1);
    }
}
sigaction:

#include <signal.h>

       int sigaction(int sig, const struct sigaction act,
           struct sigaction  oact);
//sig指定信号,act新动作,oact上一个动作
The sigaction structure is defined as something like:
           
 struct sigaction {
               void     (*sa_handler)(int);//响应函数
               sigset_t   sa_mask;       //屏蔽信号集
               int        sa_flags;       //标志
           };

例子:


#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void ouch(int sig)
{
    printf("OUCH! - I got signal %d\n", sig);
}

int main()
{
    struct sigaction act;

    act.sa_handler = ouch;
    sigemptyset(&act.sa_mask);//清空屏蔽信号集
    act.sa_flags = SA_RESETHAND;//设置响应后恢复默认

    sigaction(SIGINT, &act, 0);//不关心上次动作

  while(1) {
    printf("Hello World!\n");
    sleep(1);
  }
}

发送信号:
 #include <signal.h>

       int kill(pid_t pid, int sig);
作用:进程可以通过该函数向其他进程或本身发送信号

计时函数:
#include <unistd.h>

       unsigned int alarm(unsigned int seconds);
作用:在seconds秒后安排发送一个SIGALRM信号

模拟alarm:


/*  In alarm.c, the first function, ding, simulates an alarm clock.  */

#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

static int alarm_fired = 0;

void ding(int sig)
{
    printf("本进程%d,父进程%d\n",getpid(),getppid());
    alarm_fired = 1;
}

/*  In main, we tell the child process to wait for five seconds
    before sending a SIGALRM signal to its parent.  */

int main()
{
    pid_t pid;

    printf("alarm application starting\n");
//新建子进程
    pid = fork();
    switch(pid) {
    case -1:
      /* Failure */
      perror("fork failed");
      exit(1);
    case 0://子进程向父进程发送SIGALARM信号
      /* child */
        sleep(5);
        kill(getppid(), SIGALRM);
        exit(0);
    }

/*  The parent process arranges to catch SIGALRM with a call to signal
    and then waits for the inevitable.  */
    printf("waiting for alarm to go off\n");
    //注册响应事件
    (void) signal(SIGALRM, ding);//定义父进程接收到SIGALRM信号的响应函数

    pause();//把程序挂起直到有一个信号出现为止
    if (alarm_fired)
        printf("Ding!\n");

    printf("done\n");
    exit(0);
}



猜你喜欢

转载自blog.csdn.net/yanshaoshuai/article/details/81084840