【问题标题】:How do Multi-process use the same ncurses screen?多进程如何使用相同的 ncurses 屏幕?
【发布时间】:2016-11-05 06:57:46
【问题描述】:

我正在用 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;
}

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

我该如何解决?

【问题讨论】:

  • 您可能需要线程而不是单独的进程。
  • 使用线程可以工作,谢谢。但这是一项需要使用多进程来实现的功课。 ^_^ @πάνταῥεῖ

标签: c++ multiprocessing ncurses


【解决方案1】:

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

#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;
}

【讨论】:

    【解决方案2】:

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

    由于你使用的是fork(而不是vfork),两个进程应该有独立的地址空间,一个进程应该没有办法刷新一个在其他进程中修改的窗口。在某些情况下,开发人员选择将vforkfork 等同起来。对于 Linux,vfork manual page comments

    标准说明
    (来自 POSIX.1)vfork() 函数与 fork(2) 的效果相同, 如果进程由 vfork() 创建,则行为是 undefined 要么修改除 pid_t 类型变量之外的任何数据 存储 vfork() 的返回值,或从函数返回 调用了哪个 vfork(),或在成功调用 _exit(2)exec(3) 系列函数之一之前调用了任何其他函数。

    但接着说

    标准对vfork()的要求 那些放在 fork(2) 上的,所以两者都是 同义词是兼容。特别是,程序员不能依赖 在父级保持阻塞直到子级终止或 调用 execve(2),并且不能依赖于任何特定行为 尊重共享内存。

    weakercompliant 是一位开发人员认为让这两个功能相似并不重要...

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

    子进程和父进程运行在单独的内存中 空格。在 fork() 时,两个内存空间相同 内容。内存写入、文件映射 (mmap(2)) 和取消映射 (munmap(2)) 由其中一个进程执行不会影响 其他。

    但我们在vfork 的描述中留下了模棱两可的地方。作为 vfork 行为的一部分,您的程序可能无法更新属于父进程的窗口 - 并且在建议的答案中刷新 both 窗口仅确认 fork 函数是 vfork in伪装。

    POSIX 目前没有vfork 的页面。它有one herefork 的描述值得一读)。

    不管怎样,使用vfork 并不会真正改善事情。如果您必须在相同的地址空间内工作,那就是线程的用途。如果您必须使用单独的进程,则让一个进程更新屏幕而其他进程与管道通信是人们实际所做的。

    评论建议fork 已过时。 POSIX 在这方面有不同的说法。引用posix_spawn 的基本原理:

    引入了 posix_spawn() 函数及其密切关系 posix_spawnp() 以克服以下对于 fork() 的感知困难:如果不进行交换或动态地址转换,则 fork() 函数很难或不可能实现。

    • 对于实时环境,交换通常太慢。

    • 动态地址转换并非在 POSIX 可能有用的任何地方都可用。

    • 进程太有用了,当它必须在没有地址转换或其他 MMU 服务的情况下运行时,不能简单地选择退出 POSIX。

    因此,POSIX 需要无需地址转换或其他 MMU 服务即可有效实现的进程创建和文件执行原语。

    posix_spawn() 函数可作为库例程实现,但 posix_spawn() 和 posix_spawnp() 都设计为内核操作。此外,尽管它们可能是许多 fork()/exec 对的有效替代品,但它们的目标是为使用 fork() 有困难的系统提供有用的进程创建原语,不提供直接替代对于 fork()/ exec。

    进一步阅读:

    【讨论】:

    • 感谢您花时间解释。
    • 回复:POSIX 和vfork()vfork() 已被 POSIX 2008 淘汰,任何使用 vfork() + execve() 的东西都应该更好地使用 posix_spawn()
    • 我经常使用fork() 而不使用exec()。我当然希望它不会过时。它在服务器中非常有用。你listen()accept()fork() 甚至更好,你fork() 和每个子进程调用listen() + accept()exec() 打破了该方案,使其无法获得这样的优化(Apache 使用 fork() + listen() 方案,这是其良好速度的原因之一。)
    猜你喜欢
    • 1970-01-01
    • 2015-03-25
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-03
    • 1970-01-01
    相关资源
    最近更新 更多