highgui and fork()

asked 2015-08-26 09:11:54 -0500

icv gravatar image

Hi all!

I'm using OpenCV in a project at work, I won't enter in details because the algorithm is irrelevant for my problem. The thing is, my program uses one or more processes as it listens on a socket and then accept incoming connections by fork()-ing to dispatch clients into child programs. After the call to fork() trying to display an image with imshow() just doesn't work.

Calling to imshow() and then waitKey(0) doesn't display anything and then the window hangs (on Ubuntu, it becomes "shadowed" which means that window isn't responding to the WM anymore).

As I need to be able to see some images (results of my algorithm), I need to be able to successfully display some images that a child program generates. I also noticed that some errors appears when calling waitKey(), imshow() by itself doesn't show errors neither works as expected.

1) Is it possible to call imshow() and waitKey() from a child after fork()?

2) Is it possible to do the same from the parent after calling fork()? It seems to be problematic too.

3) Is there another way to display images from the child?

4) Why does this happens? I want to know because I want to get a deeper understanding in this and why this fails to avoid future problems and well... to learn :)

In case it helps, I'm attaching some code that I used to reproduce this issue.

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
//#include <thread>
#include <X11/Xlib.h>

/* Test cases:
 * compile with values from 1 to 4 to check where
 * the program is failing
 */
#define TEST_CASE 1

using namespace cv;

int main(int argc, char **argv) {

    Mat img;
    pid_t pid;

    if (argc > 1)
        img = imread(argv[1]);

    // XInitThreads(); /* I don't know if I have to use this one */
    imshow("first one", img);

    waitKey(0);
    pid = fork();


    /* since xorg may show error messages asynchronously 
     * we're addin a little delay */
#if TEST_CASE == 1
    fprintf(stderr, "first call to waitKey(0) after fork()\n");
    waitKey(0);
    usleep(100000);
    fprintf(stderr, "after fork() and waitKey(0)\n");
#endif

    if (pid < 0) {
        fprintf(stderr, "Error while forking..\n");
        exit(-1);
    }

    if (pid == 0) {
        /* child */
#if ((TEST_CASE == 2) || (TEST_CASE == 4))
        /* child process will just display a black image */
        Mat black = Mat::zeros(img.rows, img.cols, img.type());
        fprintf(stderr, "Child before imshow\n");
        imshow("child", black);
        fprintf(stderr, "Child after imshow\n");
#endif
    } else {
        /* parent */
#if ((TEST_CASE == 3) || (TEST_CASE == 4))
        /* parent process will just display a white image */
        Mat white = Mat::ones(img.rows, img.cols, img.type());
        fprintf(stderr, "Parent before imshow\n");
        imshow("parent", white);
        fprintf(stderr, "Parent after imshow\n");
#endif
    }

    waitKey(0);

    return 0;
}

Program output is this:

$ ./forking ../../images/malezas.jpg 
first call to waitKey(0) after fork()
first call to waitKey(0) after fork()
[xcb] Unknown sequence number while processing queue
[xcb ...
(more)
edit retag flag offensive close merge delete

Comments

just saying, select() would make it possible to do it all in a single main thread..

berak gravatar imageberak ( 2015-08-26 09:25:53 -0500 )edit

Thanks @berak, I've researched a bit about select() and I think I can adapt my program for it, your response was really helpful. But maybe in future I'll need to use fork() again.

I still wanna know why does imshow() and waitKey() behaves this way when a call to fork() was issued.

Thanks again!

icv gravatar imageicv ( 2015-08-26 11:19:38 -0500 )edit

Hi icv, I'm experiencing the same issue you did. Have you managed to understand the root cause of the issue? Thanks in advance Leonid N.

bln008 gravatar imagebln008 ( 2017-01-20 05:25:59 -0500 )edit