Click here to Skip to main content
15,888,286 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm working on an MFC application, written in visual C++ in visual studio 2015. I'm calling a function of an object using a pointer to it. I get the exception "Access Violation reading location 0x4a522c31" here:

C++
void Handler::NotifyEvent(I_Handler::eNotification nNotification){
	  for (t_InterfaceList::const_iterator iter = m_oClientList.begin(); iter != m_oClientList.end(); iter++){
	  (*iter)->I_Handler_OnEvent(nNotification);
	   }
    }


The full error message is as follows: Exception thrown at 0x6ce42dc6 (ucrtbase.dll) in program.exe: 0xc000005: Access violation reading location 0x4a522c31. It happens when calling I_Handler_OnEvent().

The class Handler is this:

C++
class Handler{
  typedef list<I_Handler*> t_InterfaceList;
  t_InterfaceList m_oClientList;
  static Handler* GetInstance();
  bool AddClient(I_Handler * pInterface);
  bool RemoveClient(I_Handler * pInterface);
  void OnTimer();
  void NotifyEvent(I_Handler::eNotification nNotification);
}

The class I_Handler is this:
C++
class I_Handler {
  public:
    virtual void I_Handler_OnEvent(eNotification nNotification) = 0;
};

The software works like this:

- The class Handler has a list of clients, who are of class I_Handler.
- When something happens inside OnTimer(), the clients must be notified.
- To notify them, inside OnTimer(), NotifyEvent() gets called.
- NotifyEvent() iterates over the list of clients and calls each function I_Handler_OnEvent()

I have a class somewhere else that controls a window (it's a CFormView) and it's also a client of Handler, meaning that this class is something like this:
C++
class View_Control : public CFormView, public I_Handler{
  DECLARE_DYNCREATE(View_Control)
  protected:
    View_Control();
    virtual ~View_Control();
  public:
    void I_Handler_OnEvent(eNotification nNotification) override;
}


std::async is used to launch tasks in parallel in different functions inside the class Handler. Inside the function OnTimer() I check for the task to be ready with a wait_for on the future object returned by std::async. When I get std::future_status::ready, I call NotifyEvent() and everything crashes. Note that if I comment out the std::async call, then the task is not run and NotifyEvent() works as intended.

What I have tried:

I have checked and the pointer address is correct, it points to the object of class 'View_Control' who registered as client.

'AddClient' gets called inside a function of ControlView, like this:
Handler::GetInstance()->AddClient(this). I checked this and *iter, they always have different values, but are close (in one execution, *iter was 0x00595E78 and this was 0x00595DA8. However, the exception always happens reading the same address, which is nowhere near these pointers.

It looks as though the fact that a function executes in other thread created by std::async breaks the ability of NotifyEvent() to call a member function by a pointer to the object.

Why does this happen?
Posted
Updated 13-Dec-16 2:07am

1 solution

MFC classes are not thread safe but std::async will probably create a new thread to execute the function which is then the reason for the access violation when calling a MFC member function from a different thread.

The common solution with MFC classes is posting user defined messages (WM_APP+xxx) and handling these in your derived classes.

In your case you can modify the client list to contain the window handles of the MFC controls instead of the objects and use PostMessage to send the user defined message with the notification code to each registered window. The message loop of the controls which is exetued by the GUI thread will then call the handler for the user defined message.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900