【问题标题】:Can I set the process group of an existing process?我可以设置现有进程的进程组吗?
【发布时间】:2009-08-21 20:44:36
【问题描述】:

我有一堆迷你服务器进程正在运行。它们与我需要停止的 FastCGI 服务器位于同一进程组中。 FastCGI 服务器将杀死其进程组中的所有内容,但我需要这些迷你服务器继续运行。

我可以更改正在运行的非子进程(它们是 PID 1 的子进程)的进程组吗? setpgid() 以“没有这样的过程”失败,尽管我很肯定它在那里。

这是在 Fedora Core 10 上。

注意进程已经在运行。新服务器做setsid()。这些是由旧代码生成的一些服务器,但没有。

【问题讨论】:

    标签: linux


    【解决方案1】:

    您可以尝试的一件事是在迷你服务器中执行 setsid()。这将使他们成为会议流程组的领导者。

    另外,请记住,您不能从另一个会话将进程组 ID 更改为一个,并且您必须从要更改组的进程中调用来更改进程组,或来自进程的父进程。

    我最近编写了一些测试代码来定期更改一组进程的进程组,以完成一项非常相似的任务。您不需要定期更改组 ID,只是我认为我可能会避开某个脚本,该脚本会定期检查运行时间超过一定时间的组。它还可以帮助您跟踪使用 setpgid() 时遇到的错误:

    #include <stdlib.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <string.h>
    
    void err(const char *msg);
    void prn(const char *msg);
    void mydaemon();
    
    int main(int arc, char *argv[]) {
    
        mydaemon();
        if (setsid() < 0)
            err("setsid");
    
        int secs = 5*60;
    
        /* creating a pipe for the group leader to send changed
           group ids to the child */
        int pidx[2];
        if (pipe(pidx))
            err("pipe");
    
        fcntl(pidx[0], F_SETFL, O_NONBLOCK);
        fcntl(pidx[1], F_SETFL, O_NONBLOCK);
    
        prn("begin");
    
        /* here the child forks, it's a stand in for the set of
           processes that need to have their group ids changed */
        int child = fork();
        switch (child) {
        case -1: err("fork3");
        case  0:
            close(pidx[1]);
    
            while(1) {
                sleep(7);
                secs -= 7;
                if (secs <= 0) { prn("end child"); exit(0); }
    
                int pid;
    
                /* read new pid if available */
                if (read(pidx[0], &pid, sizeof pid) != sizeof pid) continue;
    
                /* set new process group id */
                if (setpgid(getpid(), pid)) err("setpgid2");
    
                prn("child group changed");
            }
        default: break;
        }
    
        close(pidx[0]);
    
        /* here the group leader is forked every 20 seconds so that
           a new process group can be sent to the child via the pipe */
        while (1) {
            sleep(20);
    
            secs -= 20;
    
            int pid = fork();
            switch (pid) {
            case -1: err("fork2");
            case  0:
                pid = getpid();
    
                /* set process group leader for this process */
                if (setpgid(pid, pid)) err("setpgid1");
    
                /* inform child of change */
                if (write(pidx[1], &pid, sizeof pid) != sizeof pid) err("write");
    
                prn("group leader changed");
                break;
            default:
                close(pidx[1]);
                _exit(0);
            }
    
            if (secs <= 0) { prn("end leader"); exit(0); }
        }
    }
    
    void prn(const char *msg) {
        char buf[256];
        strcpy(buf, msg);
        strcat(buf, "\n");
        write(2, buf, strlen(buf));
    }
    
    void err(const char *msg) {
        char buf[256];
        strcpy(buf, msg);
        strcat(buf, ": ");
        strcat(buf, strerror(errno));
        prn(buf);
        exit(1);
    }
    
    void mydaemon() {
        int pid = fork();
        switch (pid) {
          case -1: err("fork");
          case  0: break;
          default: _exit(0);
        }
    
        close(0);
        close(1);
        /* close(2); let's keep stderr */
    }
    

    【讨论】:

      【解决方案2】:

      经过一番研究,我想通了。 Inshalla 遇到了根本问题,“您不能将进程组 ID 更改为另一个会话中的一个”,这解释了我的 setpgid() 失败的原因(带有误导性消息)。但是,您似乎可以从组中的任何其他进程(不一定是父进程)更改它。

      因为这些进程是由 FastCGI 服务器启动的,并且该 FastCGI 服务器仍在运行并且在同一个进程组中。因此问题是,如果不杀死它产生的服务器,就无法重新启动 FastCGI 服务器。我写了一个新的 CGI 程序,它在运行的服务器上做了一个setpgid(),通过一个网络请求执行它并解决了问题!

      【讨论】:

      • setpgid(2) 中的错误值:ESRCH ... For setpgid([pid, pgid]): pid is not the calling process and not a child of the calling process. 有趣的是,无论如何您都可以从组内设置。
      • 是的,我得到了 ESRCH,在这种情况下它的字符串化很差,因为“没有这样的过程”。
      【解决方案3】:

      听起来您实际上想要守护进程而不是移动进程组。 (注意:可以移动进程组,但我相信你需要在同一个会话中,并且目标需要已经是一个进程组。)

      但首先,看看守护进程是否适合你:

      #include <unistd.h>
      #include <stdio.h>
      
      int main() {
        if (fork() == 0) {
          setsid();
          if (fork() == 0) {
            printf("I'm still running! pid:%d", getpid());
            sleep(10);
          }
          _exit(0);
        }
      
        return 0;
      }
      

      显然您应该在实际代码中实际检查错误等,但以上应该可以工作。

      即使主进程退出,内部进程也会继续运行。从/proc 查看内部进程的状态,我们发现它确实是init 的子进程:

      Name:   a.out
      State:  S (sleeping)
      Tgid:   21513
      Pid:    21513
      PPid:   1
      TracerPid:      0
      

      【讨论】:

        猜你喜欢
        • 2010-09-24
        • 1970-01-01
        • 2019-01-21
        • 1970-01-01
        • 1970-01-01
        • 2013-06-11
        • 1970-01-01
        • 2011-12-12
        • 2013-05-17
        相关资源
        最近更新 更多