多进程如何使用同一个ncurses屏幕?

How do Multi-process use the same ncurses screen?

我正在用 ncurses 编写一个 c++ 多进程程序。

每个进程都需要在屏幕上显示一些东西。

我的示例代码:

int main() {
  initscr();
  noecho();
  curs_set(0);

  int flag = fork();
  if (flag == -1)
    exit(1);
  else if (flag == 0) {
    WINDOW *win = newwin(4, 4, 0, 0);
    int n = 0;
    while (1) {
      mvwprintw(win, 0, 0, "%d", n % 9);
      wrefresh(win);
      n = (n + 1) % 9;
      sleep(1);
    }
  }
  else {
    WINDOW *win = newwin(4, 4, 8, 8);
    int n = 0;
    while (1) {
      mvwprintw(win, 0, 0, "%d", n % 9);
      wrefresh(win);
      n = (n + 1) % 9;
      sleep(1);
    }
  }
  endwin();

  return 0;
}

但它只能在屏幕上显示一个进程的信息。

我该如何解决?

我破解了一些丑陋的东西,它大致可以工作,但显示了问题所在。我怀疑与其他进程通信的单个 window 管理器进程会更好 - 或者一些可怕的互斥锁集。

#include <stdlib.h>
#include <unistd.h>
#include <curses.h>
int main() {
  initscr();
  noecho();
  curs_set(0);
    WINDOW *win0 = newwin(4, 4, 0, 0);
    WINDOW *win1 = newwin(4, 4, 8, 8);

  int flag = fork();
  if (flag == -1)
    exit(1);
  else if (flag == 0) {
    int n = 0;
    while (1) {
      mvwprintw(win0, 0, 0, "%d", n % 9);
      wrefresh(win0);
      wrefresh(win1);
      n = (n + 1) % 9;
      sleep(1);
    }
  }
  else {
    int n = 0;
    while (1) {
      mvwprintw(win1, 0, 0, "%d", n % 9);
      wrefresh(win1);
      wrefresh(win0);
      n = (n + 1) % 9;
      sleep(1);
    }
  }
  endwin();

  return 0;
}

该示例创建两个 4x4 windows,第二个偏移量为 8,8。所以他们没有共同点。

因为您使用的是 fork(而不是 vfork),所以这两个进程应该有单独的地址 spaces ,并且一个进程应该没有办法 refresh a window 在另一个进程中 modified 。在某些情况下,开发人员选择等同于 vforkfork。对于 Linux,vfork manual page comments:

Standard Description
(From POSIX.1) The vfork() function has the same effect as fork(2), except that the behavior is undefined if the process created by vfork() either modifies any data other than a variable of type pid_t used to store the return value from vfork(), or returns from the function in which vfork() was called, or calls any other function before successfully calling _exit(2) or one of the exec(3) family of functions.

但接着说

The requirements put on vfork() by the standards are weaker than those put on fork(2), so an implementation where the two are synonymous is compliant. In particular, the programmer cannot rely on the parent remaining blocked until the child either terminates or calls execve(2), and cannot rely on any specific behavior with respect to shared memory.

较弱兼容是一位开发人员,他们认为使这两个功能相似并不重要...

fork manual page 断言有单独的地址 spaces:

The child process and the parent process run in separate memory spaces. At the time of fork() both memory spaces have the same content. Memory writes, file mappings (mmap(2)), and unmappings (munmap(2)) performed by one of the processes do not affect the other.

但我们在 vfork 的描述中留下了歧义。作为此 vfork 行为的一部分,您的程序可能无法更新属于父进程的 window — 并在建议的答案中刷新 both windows只是确认 fork 函数是 vfork 伪装的。

POSIX 当前没有 vfork 的页面。它有 one here (the fork 描述值得一读。

无论哪种方式,使用 vfork 实际上都不会改善情况。如果您必须在同一地址 space 内工作,这就是线程的用途。如果您必须使用单独的进程,让一个进程更新屏幕并让其他进程与管道通信是人们实际做的。

一条评论表明 fork 已过时。 POSIX 在这方面有不同的说法。引用 posix_spawn 的理由:

The posix_spawn() function and its close relation posix_spawnp() have been introduced to overcome the following perceived difficulties with fork(): the fork() function is difficult or impossible to implement without swapping or dynamic address translation.

  • Swapping is generally too slow for a realtime environment.

  • Dynamic address translation is not available everywhere that POSIX might be useful.

  • Processes are too useful to simply option out of POSIX whenever it must run without address translation or other MMU services.

Thus, POSIX needs process creation and file execution primitives that can be efficiently implemented without address translation or other MMU services.

The posix_spawn() function is implementable as a library routine, but both posix_spawn() and posix_spawnp() are designed as kernel operations. Also, although they may be an efficient replacement for many fork()/ exec pairs, their goal is to provide useful process creation primitives for systems that have difficulty with fork(), not to provide drop-in replacements for fork()/ exec.

进一步阅读: