You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

X11连接活跃时创建子进程的崩溃问题解决方案

问题描述

我有一个基于Linux下X11的GLUT图形应用,想要创建子进程执行辅助任务,但子进程会崩溃并出现如下错误:

X connection to :0 broken (explicit kill or server shutdown).

看起来子进程继承了X11连接,我尝试为所有文件描述符设置FD_CLOEXEC,但没有效果。请问在X11连接活跃时是否可以创建子进程?

最小复现示例报错

以下是使用GLUT和传统OpenGL编写的最小复现示例,其报错与实际应用略有不同,但仍能复现问题:

Resource temporarily unavailable
status=139
[xcb] Unknown sequence number while processing queue
[xcb] You called XInitThreads, this is not your fault
[xcb] Aborting, sorry about that.
Repro: xcb_io.c:278: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
Aborted (core dumped)

代码文件

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(Repro CXX)
cmake_policy(SET CMP0072 NEW)

find_package(GLUT REQUIRED)
if(NOT GLUT_FOUND)
    message(ERROR "GLUT not found!")
endif(NOT GLUT_FOUND)
find_package(OpenGL REQUIRED)
if(NOT OpenGL_FOUND)
    message(ERROR "OpenGL not found!")
endif(NOT OpenGL_FOUND)

add_executable(Repro main.cpp)
target_include_directories(Repro PRIVATE ${GLUT_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR})
target_link_libraries(Repro PRIVATE ${GLUT_LIBRARIES} ${OPENGL_LIBRARY})

main.cpp

#include <GL/gl.h>
#include <GL/glut.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cstdio>

static void handleDisplay(void) {
  glClearColor(0.1, 0.1, 0.1, 0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glBegin(GL_TRIANGLES);
  glVertex2i(0, 0);
  glVertex2i(1, 0);
  glVertex2i(0, 1);
  glEnd();
  glutSwapBuffers();
  glutPostRedisplay();
}

static void handleKeyboard(unsigned char key, int x, int y) {
  if (key == 'f') {
    const int pid = fork();
    if (pid == -1) {
      return;
    }

    if (pid == 0) {
      exit(0);
    } else {
      int status{};
      waitpid(pid, &status, 0);
      perror("");
      printf("status=%d\n", status);
    }
  }
}

int main(int argc, char **argv) {
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA);
  glutCreateWindow("Repro");
  glutDisplayFunc(handleDisplay);
  glutKeyboardFunc(handleKeyboard);
  glutMainLoop();
}
解决方案

在X11连接活跃时可以创建子进程,但必须避免子进程继承并干扰父进程的X11连接。你的问题根源在于:

  • 子进程继承了父进程的X11套接字文件描述符,即使设置FD_CLOEXEC,GLUT/Xlib也可能未正确给该描述符标记此属性。
  • 子进程退出时,操作系统会关闭该描述符副本,导致X11服务器误判连接已终止,父进程继续使用该连接时会触发序列号不匹配的断言错误。

具体修复步骤

  1. 子进程主动关闭X11连接
    在子进程执行任何任务前,调用XCloseDisplay()关闭继承的显示连接。需要先引入<X11/Xlib.h>头文件,修改后的handleKeyboard函数如下:
#include <X11/Xlib.h>

static void handleKeyboard(unsigned char key, int x, int y) {
  if (key == 'f') {
    const int pid = fork();
    if (pid == -1) {
      perror("fork failed");
      return;
    }

    if (pid == 0) {
      // 关闭子进程继承的X11连接
      Display* dpy = glutGetDisplay();
      if (dpy) {
        XCloseDisplay(dpy);
      }
      // 在此执行你的辅助任务
      exit(0);
    } else {
      int status{};
      waitpid(pid, &status, 0);
      perror("waitpid");
      printf("status=%d\n", status);
    }
  }
}
  1. 子进程避免调用任何GLUT/Xlib接口
    子进程应完全脱离父进程的图形上下文,仅执行非图形相关的辅助任务,比如文件处理、计算任务等。

原理说明

X11连接基于套接字实现,父子进程会共享该套接字的文件描述符。子进程主动关闭Display会正确终止自身的X11会话,避免操作系统在子进程退出时关闭套接字副本,从而保证父进程的X11连接不受干扰。

内容的提问来源于stack exchange,提问作者Maciej Dziuban

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 23:15:39