C++ on MFC multithreaded programming considerations

  • 2020-04-02 03:08:59
  • OfStack

In multithreaded programming, the simplest method is nothing more than to use AfxBeginThread   To create a worker thread, take a look at the function description:


CWinThread* AFXAPI AfxBeginThread(
AFX_THREADPROC pfnThreadProc,
LPVOID pParam,
int nPriority = THREAD_PRIORITY_NORMAL,
UINT nStackSize = 0,
DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);

In this specification, all parameters except the first and second have default values. Therefore, when we use it, we must specify the first two parameters.

The first parameter is the name of the function to be run.

The second argument, which specifies the parameter to run the function, is of type LPVOID. Therefore, the function to be run must be converted to type LPVOID after passing through.

There is also a limitation on the parameters to run, which is that a result of type UINT must be returned. So the function that you're going to run has a basically fixed format.

UINT RunProce (LPVOID lpParam)

It is also important to note that this function cannot be an instance function, that is, it cannot be preceded by a class qualifier ::. It's fine if it's a static function.

In this function, we can only use one parameter, and the type of the parameter can only be LPVOID, you can use a structure to close more than one parameter.

The rest, not so much.

So let's stop here for multithreading!

In multithreaded programming, it is important to inform the interface thread of the thread's progress, and to do some display updates. If download thread, in due course, can update the interface, now download to what progress. And so on. But in a worker thread, it is not the control that directly operates on the interface thread. So what do you do? You can only do this by customizing a message.

The workflow is to notify the interface to do some updates by sending a message on the interface in a custom thread. One detail to work out in this custom message is that the custom message must specify the control handle to receive the message. Of course you can solve this by using m_pApp to inform the main frame directly, but this solution seems to come full circle. The solution is simply to pass the handle to the control that receives the message to the custom thread. We can solve this problem by using this handle directly in the thread.

We know that the base class of the control is CWnd. So we pass a pointer to CWnd in. And of course there are other parameters that have to be passed in together, so let's make a structure


typedef struct{
 CString srcString;
 CString DesString;
 CWnd*    hander;
}Param;

Here we're passing three arguments two strings and a pointer.

Let's start with a custom thread function


UINT RunProce(LPVOID lpParam)
{
    Param* par;
    CWnd* hander;
    par = (Param*)lpParam;
    hander = par->hander;
    myCopyDirectory(lpParam);
    CString str;
    str = " Copy complete ";
    hander->SendMessage(WM_USERMESSAGE,0,(LPARAM)&str);
    return 0;
}

In this function, to run a thread composed of this function, we need to pass an argument, lpParam, which is specified by the structure of Param. It's actually passing in three parameters.


Param* par;
par = (Param*)lpParam;

We'll use the cast method in here to restore the value of the parameter. According to these three parameters   The custom thread function is ready to run. So how do you tell the interface thread? Take a look at this line in the custom function

Hander - > SendMessage (WM_USERMESSAGE, 0, (LPARAM) & STR);

  The hander in this sentence is the handle to the control that receives the message converted from the structure. The control's SendMessage method is then called to send a message to the control. The contents of the message are determined by the following parameters

The first parameter WM_USERMESSAGE is the name of a message. The name is actually a number. We need to specify the following format in the.h file

# define WM_USERMESSAGE 11130

The Numbers in the back are bigger, haha

The second and third arguments are the message-passing values, so if you don't need to pass the values, just write 0

Here we want to pass a string on the third argument that we pass, and that's how we wrote it.

That way, we're done with the part of the thread that sends the message. If a message is sent, how can it be received?

This is really an important question

First, you map the message. The purpose of message mapping is to tell the program which function to use when the message appears. In this case, you first need a message mapping function. The function for this message mapping is not scribbled, because it is passing two arguments, so the function needs to be able to receive both arguments. The handler is usually written like this

LRESULT CCopyfileDlg::OnProcName(WPARAM WPARAM, LPARAM LPARAM)
His grandmother's. It's amazing. The return value can only be LRESULT. I don't think we need to discuss this. Copy it. The function name is followed by two arguments. This is an instance function. Because there is...
The two parameters are usually written like this.

The function content is determined by the function of your program. Let me just copy a piece of my own code


LRESULT CCopyfileDlg::OnProcName(WPARAM wParam, LPARAM lParam)
{
  //TODO: handles user-defined messages
  CString* str = (CString*)lParam;
  SetDlgItemText(IDC_STATIC,*str);

  if(*str == " Copy complete ")
   {
     (CButton*)GetDlgItem(IDC_COPYBUT)->EnableWindow(true);
   }

  return 0;

}

This procedure is based on the parameters passed over the parameters, in the interface to display the specific parameters.

SetDlgItemText (IDC_STATIC, * STR);   // displays the message in the static text box.

Remark:

If you want the button to be grayed out, use the EnableWindow method of the control.

This method, let's say, is a specialized message handler, so its declaration is also special. I have to write it like this

Afx_msg LRESULT OnProcName(WPARAM WPARAM, LPARAM LPARAM);
Just put the above content in a reasonable place in the h file.

Now we have the message handler. But how do you map?

In fact, in the CPP file, there is a region included by BEGIN_MESSAGE_MAP(CCopyfileDlg, CDialog) and END_MESSAGE_MAP(). This area is used to define the message mapping.

Put this sentence between them, it is OK

ON_MESSAGE (WM_USERMESSAGE OnProcName)
In this sentence, WM_USERMESSAGE is combined with OnProcName and message handler. Isn't it super easy!

This completes the message handling part of our interface thread.

When a message is sent, it is processed by the message map in the corresponding function.

The above is all the content of this article, I hope you can enjoy it.


Related articles: