Strange behavior when multithreading using wxWidgets

There are 2 threads in my application - one UI, and the second is updating some data. The class of the second thread inherits the wxThread class, and has some variables, in particular, Worker *worker.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Worker {
public:
    virtual void work() {}
};

class WorkerThread : public wxThread {
public:
    bool isRunning = true;
    Worker *worker;

    virtual ExitCode Entry() {
        while (isRunning) {
            if (worker == nullptr) continue;
            // I understand that it is unsafe - the pointer
            // could already become nullptr,
            // but this is done solely for example
            worker->work(); 
            usleep(UPDATE_DELAY_USEC);
        }

        std::cout << "Done\n";

        return 0;
    }
};


If I change the value of the worker from the first thread to nullptr, the application will continue working fine. If, for example, I change the value to new Worker() or the same value as it was, the application will close. Without any errors printed to the console.

I change this pointer in wxNotebook events:
1
2
3
4
5
6
7
8
9
10
11
12
13
void onPageChanged(wxBookCtrlEvent &event) {
    switch (event.GetOldSelection()) {
        case MNP_PROCESSES:
            workerThread->worker = nullptr;
            break;
    }

    switch (event.GetSelection()) {
        case MNP_PROCESSES:
            workerThread->worker = &processes->worker;
            break;
    }
}

The whole strange thing is that if I bring the Worker *worker to the global scope, then everything will work fine, without any errors.

1
2
3
4
Worker *worker;

class WorkerThread : public wxThread {
    ...


What is the reason?
Last edited on
> // I understand that it is unsafe - the pointer
> // could already become nullptr,
> // but this is done solely for example
OK, so how much have you deleted and paraphrased for us just for the sake of a smaller post?


Communication between threads need to be "synchronized" in some way (e.g. by using atomic variables or mutexes). Multithreading is difficult and not something you can just try and see if it works, you need to actually understand what you're doing to make it work correctly, so I think you should spend some serious time reading up on the subject before attempting.
Last edited on
OK, so how much have you deleted and paraphrased for us just for the sake of a smaller post?

Not at all, I even added a condition for checking on nullptr so that the pointer could be set to this value and no error occurred. I wanted to show that if set value to nullptr, then the application will continue to work as intended, and if not nullptr (even just the previous value!), it will close
I was able to get an error message using gdb: Thread 1 "main" received signal SIGSEGV, Segmentation fault. workerThread->worker = &processes->worker;
Last edited on
So which is the invalid pointer?
workerThread or procesess ?

And Peter87 is right, you don't just "add threads" without a damn good plan in place.

Single thread debugging is easy, you put a breakpoint in and you look around.

Debugging threads is hard - seriously hard.
https://en.wikipedia.org/wiki/Heisenbug


Your approach (as posted) is flawed.

You are paraphrasing.
Because if you want actual help (and not vague hand-waiving through ad-hoc lists of possible causes), we need actual code we can copy/paste/try for ourselves.
The problem was solved... I was looking for a problem where there is none. You are right, I would have to give the whole code. The problem was that I first created a Notebook, respectively, onPageChanged was called, in which the pointer changed, which belonged to a class that had not yet been created.
Last edited on
Registered users can post here. Sign in or register to post.