如何同步调用shell命令?

时间:2018-07-31 18:08:11

标签: c dwm

我正在尝试教dwm在每个标签(www,文件,音乐...)中打开适当的应用程序。 dwm.c中有一个名为view的函数,负责标签的切换。

void
view(const Arg *arg)
{
    if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
        return;
    /* toggle sel tagset */
    selmon->seltags ^= 1;
    if (arg->ui & TAGMASK)
        selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;

    // user specific edit
    prepareTag(arg->ui);

    focus(NULL);
    arrange(selmon);
}

我在调用prepareTag的行中添加了一行。该功能具有简单的逻辑,除了进行几次验证(应用程序已打开?;它是什么标签?),其他所有操作之后,应用程序便会自动生成。

void
spawn(const Arg *arg)
{
    if (arg->v == dmenucmd)
        dmenumon[0] = '0' + selmon->num;
    if (fork() == 0) {
        if (dpy)
            close(ConnectionNumber(dpy));
        setsid();
        execvp(((char **)arg->v)[0], (char **)arg->v);
        fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
        perror(" failed");
        exit(EXIT_SUCCESS);
    }
}

它可以工作,但是代码异步进行。更改标签后,我看到我的墙纸了,而不是在〜20-50ms之后启动了应用程序。它会引起明显的闪烁。问题是我从未使用过C,并且不知道代码异步工作的原因。我尝试使用system函数代替内置的spawn函数,但是dwm无法捕获以这种方式打开的应用程序。我可能可以使用键绑定器和一些BASH,但是方法很脏。更不用说,我希望能够使用鼠标按钮来更改标签。

万一有人需要代码库。

git clone https://git.suckless.org/dwm

1 个答案:

答案 0 :(得分:1)

如果您阅读fork()的手册,就会意识到它会创建正在运行的进程的副本。

在派生之后,两个过程彼此独立,并且可以按任何顺序进行调度。这是您看到的异步行为。

要获得同步行为,您的父进程需要等到派生进程完成(退出)。这可以通过wait()系统调用来实现。

您可以将spawn函数修改为-

void
spawn(const Arg *arg) 
{
    if (arg->v == dmenucmd)
        dmenumon[0] = '0' + selmon->num;
    if (fork() == 0) {
        if (dpy)
            close(ConnectionNumber(dpy));
        setsid();
        execvp(((char **)arg->v)[0], (char **)arg->v);
        fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
        perror(" failed");
        exit(EXIT_SUCCESS);
    } else { // fork returns a non zero pid in the parent process. So the else branch will be taken only in the parent. 
        wait(NULL); // Wait for the child process to change state. In this case exit
    }
}