wxThread->Delete() - Exception thrown: read access violation. Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
tuk1
Experienced Solver
Experienced Solver
Posts: 95
Joined: Sun Oct 08, 2017 9:36 am

wxThread->Delete() - Exception thrown: read access violation.

Post by tuk1 » Mon Jul 20, 2020 5:51 am

I'm new to threads so struggling to provide a solution to this problem.

Code: Select all

Exception thrown: read access violation.
this->**m_thread** was 0xDDDDDDDD. occurred
Overview:

wxThread to refresh a data file at specific intervals:

Code: Select all

wxThread::ExitCode ThreadTimedDataRefresh::Entry() //override
{
    //My_Diagnostic.log_UI(__FUNCTION__);


    while (!TestDestroy())
    {
        // simulates loading data
        this->Sleep(this->m_refresh_interval);

        // sends progress info
        wxThreadEvent evt(wxEVT_MY_DATA_REFRESH);
               
        wxQueueEvent(m_sink, evt.Clone());
    }
    
    wxQueueEvent(this->m_sink, new wxThreadEvent(wxEVT_MY_DATA_REFRESH_CANCELLED));
    return static_cast<wxThread::ExitCode>(nullptr);

    // data loading has finished, send the data
    wxThreadEvent* evt = new wxThreadEvent(wxEVT_MY_DATA_REFRESHED);

    wxQueueEvent(m_sink, evt);

    return static_cast<wxThread::ExitCode>(nullptr);
}

There are 2 buttons on the main panel to start/stop the thread.
Here are the button handlers:

Code: Select all

bool MAIN_FRAME::StartThreadDataRefresh()
{
	My_Diagnostic.log_UI(__FUNCTION__);
		

	int refresh_interval = std::stoi(this->m_MC->get_data("<refresh_timer_int>") ) * 1000;

	StopThreadDataRefresh();	

	m_ThreadTimedDataRefresh = new ThreadTimedDataRefresh(this, refresh_interval);

	if (m_ThreadTimedDataRefresh->Run() != wxTHREAD_NO_ERROR)
	{
		delete m_ThreadTimedDataRefresh;
		m_ThreadTimedDataRefresh = nullptr;
		wxLogError(_("Could not create the thread needed to load the data."));
		return false;
	}

	return true;
}

void MAIN_FRAME::StopThreadDataRefresh()
{
	//My_Diagnostic.log_UI(__FUNCTION__);

	if (m_ThreadTimedDataRefresh)
	{
		m_ThreadTimedDataRefresh->Delete();
		delete m_ThreadTimedDataRefresh;
		m_ThreadTimedDataRefresh = nullptr;
	}
}
Reproducing the problem:

Everything works as it should when clicking the start/stop buttons with a reasonable interval between each click.
The problem occurs(thread is running) if clicking start in rapid succession or stop in rapid succession.

Which reminds me of the old joke ....A man went to see his doctor and said, "Doctor, every time I move my arm like this it hurts. What do you recommend?" The doctor said, "Don't move your arm like that.
1.PNG
1.PNG (72.88 KiB) Viewed 525 times
2.PNG
Sometimes the state of the thread object is different depending on the combination of button clicks.
3.PNG
If I have to guess, its got something to do with the event handlers trying to delete a thread thats already been deleted due to the rapid button clicks, but shouldnt the 'if' condition prevent that from happening:

Code: Select all

if (m_ThreadTimedDataRefresh)
	{
		m_ThreadTimedDataRefresh->Delete();
		delete m_ThreadTimedDataRefresh;
		m_ThreadTimedDataRefresh = nullptr;
	}
wxWidgets(v3.1.3) - Vs2019(v142) - Win10(x64) - DialogBlocks(v5.16.5_Unicode)

User avatar
doublemax
Moderator
Moderator
Posts: 15173
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by doublemax » Mon Jul 20, 2020 6:03 am

Is this a detached thread? Detached threads delete themselves when they terminate, so you must not call delete m_ThreadTimedDataRefresh;
Use the source, Luke!

tuk1
Experienced Solver
Experienced Solver
Posts: 95
Joined: Sun Oct 08, 2017 9:36 am

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by tuk1 » Mon Jul 20, 2020 6:16 am

doublemax wrote:
Mon Jul 20, 2020 6:03 am
Is this a detached thread? Detached threads delete themselves when they terminate, so you must not call delete m_ThreadTimedDataRefresh;
Hmmmn, I'm not sure if detached or not, how to know? ....but its based on the copy-n-paste-rdy-to-go code example below.

In fact the code example seems to have the same issue, you can try yourself by clicking the buttons in rapid succession.

Code: Select all

#include <wx/wx.h>
#include <wx/arrstr.h>
#include <wx/thread.h>

// the first event reports data load progress
// the second one reports that the data loading was cancelled
// the third one sends all loaded data at once
// wxDECLARE_EVENT macros should normally be in a .h file
wxDECLARE_EVENT(wxEVT_MY_DATA_LOADING, wxThreadEvent);
wxDECLARE_EVENT(wxEVT_MY_DATA_LOADING_CANCELLED, wxThreadEvent);
wxDECLARE_EVENT(wxEVT_MY_DATA_LOADED, wxThreadEvent);

wxDEFINE_EVENT(wxEVT_MY_DATA_LOADING, wxThreadEvent);
wxDEFINE_EVENT(wxEVT_MY_DATA_LOADING_CANCELLED, wxThreadEvent);
wxDEFINE_EVENT(wxEVT_MY_DATA_LOADED, wxThreadEvent);

class DataLoadingThread : public wxThread
{
public:
    DataLoadingThread(wxEvtHandler* sink) : wxThread(wxTHREAD_JOINABLE), m_sink(sink)
    {}

protected:
    wxEvtHandler* m_sink;
    
    ExitCode Entry() override
    {   
        const size_t total = 10;
        wxArrayString* data = new wxArrayString();
        
        for ( size_t i = 0; i < total; ++i )
        {                        
            if ( TestDestroy() ) // the user cancelled data loading
            {                
                delete data;
                wxQueueEvent(m_sink, new wxThreadEvent(wxEVT_MY_DATA_LOADING_CANCELLED));
                return static_cast<wxThread::ExitCode>(nullptr);
            }

            // simulates loading data
            wxMilliSleep(250);
            data->push_back(wxString::Format("Data %zu", i + 1));

            // sends progress info
            wxThreadEvent evt(wxEVT_MY_DATA_LOADING);

            evt.SetInt((double)data->size()/total * 100);
            wxQueueEvent(m_sink, evt.Clone());
        }

        // data loading has finished, send the data
        wxThreadEvent* evt = new wxThreadEvent(wxEVT_MY_DATA_LOADED);
        
        evt->SetPayload(data);        
        wxQueueEvent(m_sink, evt);
        
        return static_cast<wxThread::ExitCode>(nullptr);
    }
};

class MyFrame: public wxFrame
{
public:   
    MyFrame() : wxFrame (NULL, wxID_ANY, "Test", wxDefaultPosition, wxSize(800, 600))
    {        
        wxPanel* mainPanel = new wxPanel(this);
        wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);

        wxButton* button = new wxButton(mainPanel, wxID_ANY, "Load data");
        mainSizer->Add(button, wxSizerFlags().Expand().Border());
        button->Bind(wxEVT_BUTTON, &MyFrame::OnLoadData, this);

        button = new wxButton(mainPanel, wxID_ANY, "Cancel data loading");
        mainSizer->Add(button, wxSizerFlags().Expand().Border());
        button->Bind(wxEVT_BUTTON, &MyFrame::OnCancelLoadingData, this);

        m_dataView = new wxListBox(mainPanel, wxID_ANY);
        mainSizer->Add(m_dataView, wxSizerFlags().Proportion(1).Expand().Border());        
                                                                                
        mainPanel->SetSizer(mainSizer);

        Bind(wxEVT_MY_DATA_LOADING, &MyFrame::OnDataLoading, this);
        Bind(wxEVT_MY_DATA_LOADING_CANCELLED, &MyFrame::OnDataLoadingCancelled, this);
        Bind(wxEVT_MY_DATA_LOADED, &MyFrame::OnDataLoaded, this);
    }
    
    ~MyFrame()
    {
        StopDataLoadingThread();
    }

private:
    wxListBox* m_dataView;
    wxThread*  m_dataLoadingThread = nullptr;

    bool StartDataLoadingThread()
    {
        StopDataLoadingThread();

        m_dataLoadingThread = new DataLoadingThread(this);
        if ( m_dataLoadingThread->Run() != wxTHREAD_NO_ERROR )
        {
            delete m_dataLoadingThread;
            m_dataLoadingThread= nullptr;
            wxLogError(_("Could not create the thread needed to load the data."));
            return false;
        }            

        return true;
    }

    void StopDataLoadingThread()
    {
        if ( m_dataLoadingThread )
        {
            m_dataLoadingThread->Delete();
            delete m_dataLoadingThread;
            m_dataLoadingThread = nullptr;
        }
    }

    // button Load data clicked
    void OnLoadData(wxCommandEvent&)
    {        
        m_dataView->Clear();
        if ( StartDataLoadingThread() )
            m_dataView->AppendString(wxString::Format("<Loading data, please wait...>"));
    }

    // button Cancel loading data clicked
    void OnCancelLoadingData(wxCommandEvent&)
    {
        StopDataLoadingThread();
    }

    // handler for wxEVT_MY_DATA_LOADING, i.e., the progress report
    void OnDataLoading(wxThreadEvent& evt)
    {
        m_dataView->SetString(0, wxString::Format("<Loading data, finished %d%%>", evt.GetInt()));    
    }

    // handler for wxEVT_MY_DATA_LOADING_CANCELLED, i.e., when the user cancelled loading data
    void OnDataLoadingCancelled(wxThreadEvent&)
    {
        m_dataView->SetString(0, "<Loading data cancelled by user>");
    }

    // handler for wxEVT_MY_DATA_LOADED, i.e., all data loaded
    void OnDataLoaded(wxThreadEvent& evt)
    {
       wxArrayString* data = evt.GetPayload<wxArrayString*>();              

       m_dataView->Clear();
       m_dataView->Append(*data);
       delete data;
    }
};

class MyApp : public wxApp
{
public:         
    bool OnInit()
    {
        (new MyFrame())->Show();               
        return true;
    }   
}; wxIMPLEMENT_APP(MyApp);
wxWidgets(v3.1.3) - Vs2019(v142) - Win10(x64) - DialogBlocks(v5.16.5_Unicode)

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 4423
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by ONEEYEMAN » Mon Jul 20, 2020 6:51 am

Hi,
Can you reproduce it in the thread sample provided with the wxWidgets?

Thank you.

tuk1
Experienced Solver
Experienced Solver
Posts: 95
Joined: Sun Oct 08, 2017 9:36 am

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by tuk1 » Mon Jul 20, 2020 12:49 pm

I don't understand all the sample code as its quite complicated, ..it seems not so easy to test as the sample doesn't have start/stop buttons like my code.

But there is an interesting comment in the equivalent function.
1.PNG
1.PNG (35.41 KiB) Viewed 481 times
Which looks like the same wxThread->Delete() that causes the error in my code.
Image

Again, Im wondering why the if condition would return true if the thread had already deleted itself ..and, why whoever wrote the sample thought this might be a possibility?

Or maybe Im barking up the wrong tree?
wxWidgets(v3.1.3) - Vs2019(v142) - Win10(x64) - DialogBlocks(v5.16.5_Unicode)

Kvaz1r
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 229
Joined: Tue Jun 07, 2016 1:07 pm

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by Kvaz1r » Mon Jul 20, 2020 1:26 pm

That comment is about detach thread, in example above thread is joinable. Btw, I can't reproduce the behaviour if I click buttons rapidly.

tuk1
Experienced Solver
Experienced Solver
Posts: 95
Joined: Sun Oct 08, 2017 9:36 am

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by tuk1 » Mon Jul 20, 2020 2:23 pm

Kvaz1r wrote:
Mon Jul 20, 2020 1:26 pm
Btw, I can't reproduce the behaviour if I click buttons rapidly.
Playing with it now, clicking the 'load data' button a second time before the progress reach 100% causes an error, ...even if you wait until 90%
1.PNG
wxWidgets(v3.1.3) - Vs2019(v142) - Win10(x64) - DialogBlocks(v5.16.5_Unicode)

User avatar
doublemax
Moderator
Moderator
Posts: 15173
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by doublemax » Mon Jul 20, 2020 3:44 pm

Although it's nice to find bugs in other samples, it's not guaranteed that these are related to your problem.

Please confirm whether you are using a detached or joinable thread. (parameter wxTHREAD_DETACHED or wxTHREAD_JOINABLE to wxThread ctor).

If it's a detached thread you must not "delete" the thread pointer. Calling Delete() is ok, if you know that the thread has not destroyed itself yet. In order to be 100% sure about this, you will need a wxMutex.

If everything fails create an as-small-as-possible compilable sample that shows the problem. If necessary add instruction on how to create the crash.
Use the source, Luke!

tuk1
Experienced Solver
Experienced Solver
Posts: 95
Joined: Sun Oct 08, 2017 9:36 am

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by tuk1 » Tue Jul 21, 2020 4:50 pm

The thread is joinable.

I had a look into wxMutex but tbh I found the example code a bit confusing, could this be a typo?

Code: Select all

s_mutexProtectingTheGlobalList->Lock();
Should it not be:

Code: Select all

s_mutexProtectingTheGlobalData->Lock();
https://docs.wxwidgets.org/3.0/classwx_mutex.html

Anyway, I couldn't get wxMutex to compile in my code, but wasn't entirely sure where to put it.
----------

As requested, I created a compilable sample that shows the problem.

There are various ways of causing the exception:
Method 1
1) Click 'Start Thread'.
2) When the counter is under way(eg reaches 3), then quickly double click 'Start Thread'.

Method 2
1) Click 'Start Thread'.
2) When the counter is under way(eg reaches 3), then quickly double click 'Stop Thread'.

Method 3
1) Click 'Start Thread'.
2) When the counter is under way(eg reaches 3), then rapidly click 'Start Thread' like its 1982 and youre playing space invaders.

Method 4
1) Click 'Start Thread'.
2) When the counter is under way(eg reaches 3), then rapidly click 'Stop Thread' like its 1982 and youre playing space invaders.
----

What doesn't cause the issue?
1) Rapidly clicking 'Stop Thread' when no thread is running

Code: Select all

#include <wx/wx.h>
#include <wx/arrstr.h>
#include <wx/thread.h>
#include <wx/listctrl.h>

#include <string>
#include <vector>


wxDECLARE_EVENT(wxEVT_INC_COUNT, wxThreadEvent);
wxDECLARE_EVENT(wxEVT_RESET_COUNT, wxThreadEvent);

wxDEFINE_EVENT(wxEVT_INC_COUNT, wxThreadEvent);
wxDEFINE_EVENT(wxEVT_RESET_COUNT, wxThreadEvent);


class MyCounter {

public:

    MyCounter() :
        m_data(),
        count(0)
    {

    }

    const std::string& at(const long& pos_) const
    {
        //---------------- | GET LOG DATA AT POS | ---------------- 

        if (!this->m_data.empty())
        {
            return this->m_data.at(pos_);
        }
       
    }

    void inc()
    {
        m_data.push_back(std::to_string(count++));
    }
    void reset()
    {
        
        this->m_data.clear();
        this->m_data.shrink_to_fit();

        count = 0;
    }

    const size_t size() const
    {
        //---------------- | GET SIZE OF DIAGNOSTIC LOG | ---------------- 

        return this->m_data.size();
    }

private:

    int count;
    std::vector<std::string> m_data;

};

class ListCtrl_CountView : public wxListCtrl {

public:

    ListCtrl_CountView::ListCtrl_CountView(
        wxWindow* parent_,
        const wxWindowID& id_,
        const wxPoint& pos_,
        const wxSize& size_,
        long style_,
        MyCounter* mc_) :
        wxListCtrl(parent_, id_, pos_, size_, style_),
        m_counter(mc_)
    {

        //---------------- |  Add first column  | ----------------	    
        wxListItem col0;
        col0.SetId(0);
        col0.SetText(_("Count..."));
        col0.SetWidth(575);
        InsertColumn(0, col0);

    }

    const int GetSelection() const
    {
        //---------------- | RETURN INDEX OF SELECTED ITEM ELSE IF NO SELECTION RETURN: wxNOT_FOUND | ----------------

        long itemIndex = -1;

        while ((itemIndex = this->GetNextItem(itemIndex, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)) != wxNOT_FOUND)
        {
            if (itemIndex >= 0) { return itemIndex; }
        }

        return itemIndex;
    }

    wxString OnGetItemText(long row_, long col_) const
    {
        //---------------- | Overload virtual method of wxListCtrl to provide text data for virtual list | ----------------
        //---------------- | Get: item data | ---------------- 
        //---------------- | Use item_ and col_ to return the correct data for that particular cell | ---------------- 

        if (col_ == 0 && m_counter->size() > 0)
        {
            wxString str = m_counter->at(row_);
            return str;
        }

        return "";
    }


private:

    MyCounter* m_counter;

};


class ThreadTimedDataRefresh : public wxThread
{

public:

    ThreadTimedDataRefresh(wxEvtHandler* sink_, int interval_) :
        wxThread(wxTHREAD_JOINABLE),
        m_sink(sink_),
        m_refresh_interval(interval_)
    {
        
    }

protected:

    wxEvtHandler* m_sink;    

    int m_refresh_interval;

    ExitCode Entry() override
    {

        while (!TestDestroy())
        {
            // interval between each count
            this->Sleep(this->m_refresh_interval);

            // increment count
            wxThreadEvent evt(wxEVT_INC_COUNT);

            wxQueueEvent(m_sink, evt.Clone());
        }


        wxQueueEvent(this->m_sink, new wxThreadEvent(wxEVT_RESET_COUNT));
        return static_cast<wxThread::ExitCode>(nullptr);

        return static_cast<wxThread::ExitCode>(nullptr);
    }

};


class MAIN_FRAME : public wxFrame
{

public:

    MAIN_FRAME() : 
        wxFrame(NULL, wxID_ANY, "Threaded Counter", wxDefaultPosition, wxSize(800, 600)),
        m_count_view(),
        m_count_thread(),
        m_counter()
    {
        m_counter = new MyCounter();

        wxPanel* mainPanel = new wxPanel(this);
        wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);

        wxButton* button = new wxButton(mainPanel, wxID_ANY, "Start Thread");
        mainSizer->Add(button, wxSizerFlags().Expand().Border());
        button->Bind(wxEVT_BUTTON, &MAIN_FRAME::OnCountStart, this);

        button = new wxButton(mainPanel, wxID_ANY, "Stop Thread");
        mainSizer->Add(button, wxSizerFlags().Expand().Border());
        button->Bind(wxEVT_BUTTON, &MAIN_FRAME::OnCountStop, this);
                        
        m_count_view = new ListCtrl_CountView(mainPanel, wxID_ANY, wxDefaultPosition, wxSize(600, 500), wxLC_REPORT | wxLC_VIRTUAL | wxLC_NO_SORT_HEADER | wxLC_SINGLE_SEL | wxFULL_REPAINT_ON_RESIZE, m_counter);
        m_count_view->SetFont(wxFont(7, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxT("Tahoma")));
        mainSizer->Add(m_count_view, 0, wxALIGN_CENTER_HORIZONTAL | wxALL, 5);

        mainPanel->SetSizer(mainSizer);


        Bind(wxEVT_INC_COUNT, &MAIN_FRAME::OnIncCount, this);
        Bind(wxEVT_RESET_COUNT, &MAIN_FRAME::OnResetCount, this);
                
        
    }
    ~MAIN_FRAME()
    {
        StopThreadedCount();
    }

private:    

    ListCtrl_CountView* m_count_view;
    wxThread* m_count_thread;

    MyCounter* m_counter;

    // button start count clicked
    void MAIN_FRAME::OnCountStart(wxCommandEvent&)
    {        
        StartThreadedCount();
    }

    // button stop count clicked
    void MAIN_FRAME::OnCountStop(wxCommandEvent&)
    {       
        StopThreadedCount();
    }


    bool MAIN_FRAME::StartThreadedCount()
    {

        int refresh_interval = 1000;

        StopThreadedCount();

        m_count_thread = new ThreadTimedDataRefresh(this, refresh_interval);

        if (m_count_thread->Run() != wxTHREAD_NO_ERROR)
        {
            delete m_count_thread;
            m_count_thread = nullptr;
            wxLogError(_("Could not create the thread needed to load the data."));
            return false;
        }

        return true;
    }
    void MAIN_FRAME::StopThreadedCount()
    {
        if (m_count_thread)
        {
            m_count_thread->Delete();
            delete m_count_thread;
            m_count_thread = nullptr;
        }
    }


    // handler for wxEVT_INC_COUNT
    void MAIN_FRAME::OnIncCount(wxThreadEvent& evt)
    {        
        m_counter->inc();

        this->m_count_view->SetItemCount(m_counter->size());
        this->m_count_view->Refresh();                
    }

    // handler for wxEVT_RESET_COUNT
    void MAIN_FRAME::OnResetCount(wxThreadEvent&)
    {        
        m_counter->reset();
    }
    
};

class MyApp : public wxApp
{

public:

    bool OnInit()
    {
        (new MAIN_FRAME())->Show();
        return true;
    }

}; wxIMPLEMENT_APP(MyApp);
Last edited by tuk1 on Tue Jul 21, 2020 4:52 pm, edited 1 time in total.
wxWidgets(v3.1.3) - Vs2019(v142) - Win10(x64) - DialogBlocks(v5.16.5_Unicode)

User avatar
doublemax
Moderator
Moderator
Posts: 15173
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by doublemax » Tue Jul 21, 2020 4:52 pm

Please reduce the sample to the bare minimum to reproduce the issue.
Use the source, Luke!

tuk1
Experienced Solver
Experienced Solver
Posts: 95
Joined: Sun Oct 08, 2017 9:36 am

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by tuk1 » Tue Jul 21, 2020 4:55 pm

doublemax wrote:
Tue Jul 21, 2020 4:52 pm
Please reduce the sample to the bare minimum to reproduce the issue.
Define "bare minimum" ?
wxWidgets(v3.1.3) - Vs2019(v142) - Win10(x64) - DialogBlocks(v5.16.5_Unicode)

User avatar
doublemax
Moderator
Moderator
Posts: 15173
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by doublemax » Tue Jul 21, 2020 4:57 pm

Remove everything that's not essential to reproduce the issue. E.g. i'm pretty sure the wxListCtrl is not part of the problem.
Use the source, Luke!

tuk1
Experienced Solver
Experienced Solver
Posts: 95
Joined: Sun Oct 08, 2017 9:36 am

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by tuk1 » Tue Jul 21, 2020 5:06 pm

Well, you asked for a minimized version of the real code( which does include wxListCtrl ), I'm not sure how to create a 'working' example of the real code once I remove the bare bones that makes the code work, sure I could create another code example that shows the issue but then that wouldn't be my code ....I already posted one of those earlier in the thread.

Is there a reason you cant take a look with wxListCtrl included ..as you say its not part of the problem, so why remove it?
wxWidgets(v3.1.3) - Vs2019(v142) - Win10(x64) - DialogBlocks(v5.16.5_Unicode)

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 4423
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by ONEEYEMAN » Tue Jul 21, 2020 5:17 pm

Hi,
There is a reason it's called MINIMAL...

Thank you.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2569
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxThread->Delete() - Exception thrown: read access violation.

Post by PB » Tue Jul 21, 2020 5:26 pm

FWIW: the code posted in viewtopic.php?f=1&t=47358#p199921 lacks the source of origin but looks as one of mine.

I cannot reproduce the issue there; however, race conditions are very timing sensitive and may not demonstrate on specific setup. I certainly do not have a gamer mouse or click speed.

I hazily remember that one of my such examples may have had a race condition but looking at the code now, I cannot see it.

The event handling is done in the main thread so it is always serialized and the execution of event handlers (and hence StartDataLoadingThread() and StopDataLoadingThread() cannot overlap.

But I wasted at almost an hour (very frustrating one) hunting for a superstupid bug of mine in a very simple code just few days ago, so my confidence in debugging abilities is not very high....
Last edited by PB on Tue Jul 21, 2020 5:33 pm, edited 1 time in total.

Post Reply