| |

VerySource

 Forgot password?
 Register
Search
View: 1331|Reply: 10

I have been thinking about the problem for a few days, please come and see, I am anxious!!

[Copy link]

1

Threads

7

Posts

5.00

Credits

Newbie

Rank: 1

Credits
5.00

 China

Post time: 2020-9-25 11:30:02
| Show all posts |Read mode
This example is an example of VC++ Advanced Programming Technology and Examples Chapter 5 Multithreading
1:
Create a dialog-based program Test
2:
Place a button IDC_BT_START. and a progress bar control IDC_PROGRESS1 on the dialog
And associate a variable m_progress for IDC_PROGRESS1;
3:
In the TestDlg.h file, define a structure
struct threadInfo
{
CProgressCtrl * p_Progress;
CDialog * p_Dlg;
int second; //When the progress bar is paused

}
4:
In the TestDlg.cpp file
#define USER_PROC_FINISHED WM_USER+1

threadInfo Info;
UINT ThreadProc(LPVOID pParam)
{
threadInfo * p=(threadInfo *)pParam;
for(int i=0;i<=100;i++)
{
p->p_Progress->SetPos(i);
::Sleep(p->second*10);


}
::PostMessage(p->p_Dlg->GetSafeHwnd(),USER_PROC_FINISHED,0,0);
return 0;
}
5:
In the click response of the button IDC_BT_START:
void CTestDlg::OnBtStart()
{
To
Info.p_Progress=&m_progress;
Info.p_Dlg=this;
     Info.second=1;
AfxBeginThread(ThreadProc,&Info);
}
6:
Declare the message function in TestDlg.h
To
      .........
    //}}AFX_MSG
    afx_msg void OnFinish();
7.
In the TestDlg.cpp file
BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
         .......
ON_BN_CLICKED(IDC_BT_START, OnBtStart)
//}}AFX_MSG_MAP
ON_MESSAGE(USER_PROC_FINISHED,OnFinish)
END_MESSAGE_MAP()

void CTestDlg::OnFinish()
{
SetDlgItemText(IDC_BT_START,"Please restart after the thread ends");
}




In Hou Jieyi's book <Win32 Multithreaded Programming>, p294 says:
1:
MFC has a major limitation, which will affect almost everything you do. The mapping relationship between MFC objects and Win32 handles is recorded in thread local storage (TLS), so you have no way to remove an MFC object from a certain One thread is handed over to another thread, and you cannot pass MFC object pointers between threads. The pointers here include (not limited to) CWnd, CDC, CPen, CBrush, CFont, Cbitmap, CPalette... ....
2: This restriction means that you cannot put a pointer (pointing to a CWnd) into a structure, and the structure is used by a Worker thread, and you cannot give a pointer to CDialog or CView to another Threads.............Share objects between threads. Here is an inconvenient alternative. Don't place MFC objects. Change the handle of the object. You can use GetSateHwnd() to get Derived from the handle of the CWnd object, CDialog.

In the above procedures
void CTestDlg::OnBtStart()
{
To
Info.p_Progress=&m_progress; //Transfer the address of the progress bar, right?? The progress bar is derived from CWnd
Info.p_Dlg=this; //Pass the pointer of the dialog box, right?? The progress bar is derived from CWnd
     Info.second=1;
AfxBeginThread(ThreadProc,&Info);
}




threadInfo Info;
UINT ThreadProc(LPVOID pParam)
{
threadInfo * p=(threadInfo *)pParam;
for(int i=0;i<=100;i++)
{
p->p_Progress->SetPos(i);//Using the address of the passed progress bar, call the member function of the progress bar, right??.
::Sleep(p->second*10);


}
::PostMessage(p->p_Dlg->GetSafeHwnd(),USER_PROC_FINISHED,0,0);
        //(p->p_Dlg->GetSafeHwnd() Use the this pointer of the passed dialog box to call the member function GetSafeHwnd(), right??.
return 0;
}
Reply

Use magic Report

0

Threads

15

Posts

13.00

Credits

Newbie

Rank: 1

Credits
13.00

 China

Post time: 2020-9-26 15:00:01
| Show all posts
The books in China are not serious. Hou Jie is right, and the same is said on MSDN.

By passing HANDLE instead of a pointer to an object, you can use CWnd::FromHandle or CWnd::Attach in your worker thread to bind HANDLE to a C++ object in your worker thread.

You can also complete certain work by giving the main thread PostMessage
Reply

Use magic Report

1

Threads

7

Posts

5.00

Credits

Newbie

Rank: 1

Credits
5.00

 China

 Author| Post time: 2020-9-26 22:45:01
| Show all posts
void CTestDlg::OnBtStart()
{
AfxBeginThread(ThreadProc,GetSafeHwnd());

}

UINT ThreadProc(LPVOID pParam)
{
CTestDlg testdlg;
testdlg.Attach((HWND)pParam);
for(int i=0;i<=100;i++)
{
                    testdlg.m_progress.SetPos(i);//Operate the progress bar in the auxiliary thread
Sleep(1*10);
}
::PostMessage((HWND)pParam,USER_PROC_FINISHED,0,0);
return 0;
}

Brother, I changed the corresponding code to the above, how does the run assertion appear. Click the IDC_BT_START button to appear the assertion.
Reply

Use magic Report

0

Threads

15

Posts

13.00

Credits

Newbie

Rank: 1

Credits
13.00

 China

Post time: 2020-9-26 23:15:01
| Show all posts
Are you sure that m_progress does have a valid m_hWnd?

Or is there no reason for testdlg.Detach()?
Reply

Use magic Report

1

Threads

7

Posts

5.00

Credits

Newbie

Rank: 1

Credits
5.00

 China

 Author| Post time: 2020-9-26 23:30:01
| Show all posts
UINT ThreadProc(LPVOID pParam)
{
         CTestDlg testdlg;
testdlg.Attach((HWND)pParam);
for(int i=0;i<=100;i++)
{
                  testdlg.m_progress.SetPos(i);
Sleep(1*10);
}
To
testdlg.Detach();
::PostMessage((HWND)pParam,USER_PROC_FINISHED,0,0);

return 0;
}

Is it still not possible to change it like this??
Reply

Use magic Report

1

Threads

7

Posts

5.00

Credits

Newbie

Rank: 1

Credits
5.00

 China

 Author| Post time: 2020-9-26 23:45:01
| Show all posts
Are you sure that m_progress does have a valid m_hWnd?

To brother, you said to me. I tried it, and it was indeed you.

void CTestDlg::OnBtStart()
{
AfxBeginThread(ThreadProc,this>m_progress.GetSafeHwnd());
}

UINT ThreadProc(LPVOID pParam)
{
CProgressCtrl progress1;
progress1.Attach((HWND)pParam);
for(int i=0;i<=100;i++)
{
To
                  progress1.SetPos(i);
Sleep(1*10);
}
::PostMessage(progress1.GetParent()->GetSafeHwnd(),USER_PROC_FINISHED,0,0);
         progress1.Detach();
return 0;
}

Change it as follows.
Reply

Use magic Report

1

Threads

7

Posts

5.00

Credits

Newbie

Rank: 1

Credits
5.00

 China

 Author| Post time: 2020-9-27 01:30:02
| Show all posts
UINT ThreadProc(LPVOID pParam)
{
         CProgressCtrl* p_progress=(CProgressCtrl*)(CProgressCtrl::FromHandle((HWND)pParam));
for(int i=0;i<=100;i++)
{
To
                  p_progress->SetPos(i);
Sleep(1*10);
}
To
::PostMessage(p_progress->GetParent()->GetSafeHwnd(),USER_PROC_FINISHED,0,0);
return 0;

}
Same as above
Reply

Use magic Report

0

Threads

10

Posts

9.00

Credits

Newbie

Rank: 1

Credits
9.00

 China

Post time: 2020-9-27 06:30:01
| Show all posts
testdlg.Attach((HWND)pParam);
A window should only be attached by one object. I tracked it down, and the assertion after clicking the "Start" button appeared here.

Doing so can make testdlg.Attach((HWND)pParam); run successfully:

AfxBeginThread(ThreadProc,this->Detach());
After the ready-made is over, then this->Attach...

But it also doesn't make any sense, because after testdlg Attach is successful, monitoring can find that the member variable m_progress1 of testdlg is NULL, so it runs to
testdlg.m_progress.SetPos(i); When this sentence is used, a memory error will definitely occur.

In fact, it is said that the parameter is passed to the thread, the best is the handle, but the pointer is passed in front, and it is not good? Why do I have to pass the handle? When the handle is passed in as a parameter, it seems to be PostMessage(.. ), there is no problem, as for why you can't use it to operate the window, then you have to wait for the awesome person to appear and give an explanation!
Reply

Use magic Report

0

Threads

10

Posts

9.00

Credits

Newbie

Rank: 1

Credits
9.00

 China

Post time: 2020-9-27 07:00:01
| Show all posts
Ah, this post took too long to open...
I went down to adjust the program, and then I came up to reply. It didn't refresh. I didn't expect that the host had already solved the problem!

Learning with an open mind...
Reply

Use magic Report

1

Threads

7

Posts

5.00

Credits

Newbie

Rank: 1

Credits
5.00

 China

 Author| Post time: 2020-9-27 09:45:01
| Show all posts
Brother, let me go further and add a new member function in the dialog box
class CTestDlg: public CDialog
{
public:
void call();
     .....
}

void CTestDlg::call()
{
for(int i=0;i<=100;i++)
{
m_progress.SetPos(i);
Sleep(10);
}
   
}

Start button click function
void CTestDlg::OnBtStart()
{

AfxBeginThread(ThreadProc,GetSafeHwnd());//The handle of the incoming dialog box
}
In the thread function of ThreadProc
UINT ThreadProc(LPVOID pParam)
{

CTestDlg *p=(CTestDlg*)(CDialog::FromHandle((HWND)pParam));
p->call();
return 0;
}

This is a problem. It is p->call(); using the converted pointer to call its member function, why is this not working??
Reply

Use magic Report

You have to log in before you can reply Login | Register

Points Rules

Contact us|Archive|Mobile|CopyRight © 2008-2023|verysource.com ( 京ICP备17048824号-1 )

Quick Reply To Top Return to the list