Embedded cython in C prevents multi threading

83 Views Asked by At

I am using PyQT5 to create a GUI app. The GUI app process needs to run two threads consecutively to work. Thread #1 to run the MainWindow App and the Thread #2 (Emitter) to monitor for any incoming signals or changes to the MainWindow.

MainWindow (#1 Thread):

class MainWindow(QMainWindow, Ui_MainWindow):

    def __init__(self, queue_from_mother: Queue, queue_to_mother: Queue, emitter: Emitter):
        QMainWindow.__init__(self)
        self.queue_from_mother = queue_from_mother
        self.queue_to_mother = queue_to_mother
        self.emitter = emitter
        self.emitter.daemon = True
        self.emitter.start()

   # Much more code, but irrelevant

Emitter (#2 thread):

class Emitter(QThread):
    def __init__(self, from_process: Pipe, queue_to_mother: Queue, queue_from_mother: Queue):
    super().__init__()

def run(self):
    while True:
        GUIcmds = <list>ReadMemorySpace() # a C external Function to read from Shared memory space and return a Python object
        if("change" in GUIcmds)
            self.somelbl.emit("GUIcmds")

cdef public void mainSec():
    app = QtWidgets.QApplication(sys.argv)
    emitter = mdx.Emitter(mother_pipe, queue_to_mother, queue_from_mother)
    Dialog = mdx.MainWindow(queue_from_mother, queue_to_mother, emitter)
    Dialog.show()
    sys.exit(app.exec_())

Pure External C:

#include "mdx.h"

int main(){
     program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
    fprintf(stderr, "Fatal error: cannot decode argv[0], got %d arguments\n", argc);
    exit(1);
}


//PyImport_AppendInittab("mdx", PyInit_mdx);
if (PyImport_AppendInittab("commonmodules", PyInit_mdx) == -1) {
    fprintf(stderr, "Error: could not extend in-built modules table\n");
    exit(1);
}
Py_SetProgramName(program);

Py_Initialize();

pmodule = PyImport_ImportModule("mdx");
if (!pmodule) {
    PyErr_Print();
    fprintf(stderr, "Error: could not import module 'embedded'\n");
    return -1;
}

PyObject* sys = PyImport_ImportModule("sys");
PyObject* path = PyObject_GetAttrString(sys, "path");
PyList_Append(path, PyUnicode_FromString("."));
PyList_Append(path, PyUnicode_FromString("C:/Users/uesrname/AppData/Local/Programs/Python/python39/"));


/* 1st: Import the module */
PyObject* ModuleString = PyUnicode_FromString((char*)"mdx");
if (!ModuleString) {
    PyErr_Print();
    printf("Error formating python script\n");
}

PyObject* Module = PyImport_Import(ModuleString);
if (!Module) {
    PyErr_Print();
    printf("Error importing python script\n");
}
__pyx_f_13commonmodules_mainSec();

Py_Finalize();
}

Note: since the code is too much, I am providing only the sections relevant to the question.

The problem is that as soon as the Emitter enters the loop, the MainWindow app freezes. I believe the issue is with the python GIL, because, when I add a short timeout to the while loop time.sleep(0.3), the MainWindow become interactive.

Does anyone have a solution on how can I run Emitter without impacting or freezing the MainWindow app?

0

There are 0 best solutions below