线程函数传地址问题问题

时间:2021-08-23 18:50:51
为什么线程函数不能把结构的地址传过去,我相当郁闷

void CMainWindow::OnButtonCacl()
{
m_wndEditPO.SetWindowText(_T("0"));

m_wndEditMax.GetWindowText(strMax);
m_wndEditMin.GetWindowText(strMin);
m_wndEditTN.GetWindowText(strThreadNumber);

int nMax, nMin, nThreadNumber;
nMax = _ttoi(strMax);
nMin = _ttoi(strMin);
nThreadNumber = _ttoi(strThreadNumber);

m_wndButtonCacl.EnableWindow(FALSE);

CALCINFO* calcinfo = new CALCINFO;
calcinfo->hWnd = m_hWnd;
calcinfo->nMax = nMax;
calcinfo->nMin = nMin;
calcinfo->nThreadNumber = nThreadNumber;
calcinfo->pCs = &m_cs;

for(int i=1; i<=nThreadNumber; i++)
{
AfxBeginThread(ThreadFunc, calcinfo);
}
}

UINT ThreadFunc(LPVOID pPrama)
{
CALCINFO* pCalc = (CALCINFO*)pPrama;
int nMax = pCalc->nMax;             //这边的值都为0,为什么传不过
int nMin = pCalc->nMin;
int nThreadNumber = pCalc->nThreadNumber;
HWND hWnd = pCalc->hWnd;
CCriticalSection* pCs = pCalc->pCs;
delete pCalc;
long nStep = (nMax - nMin + 1) / nThreadNumber;
long beginValue = nMin + nStep * (nThreadNumber -1);
long endValue = beginValue + nStep;
long result = 0;
for (long i=beginValue; i<endValue; i++)
{
result += i;
}
pCs->Lock();
long sum = 0;
sum += result;
::PostMessage(hWnd, WM_USER_THREAD, (WPARAM)sum, 0);
pCs->Unlock();
return 0;
}

LRESULT CMainWindow::OnThreadFinished(WPARAM wParam, LPARAM lParam)
{
int nResult = (int)wParam;
CString strResult;
strResult.Format("%d",nResult);
m_wndEditPO.SetWindowText(strResult);
m_wndButtonCacl.EnableWindow(TRUE);
return 0;
}

void CMainWindow::PostNcDestroy()
{
// TODO: 在此添加专用代码和/或调用基类

delete this;
}

31 个解决方案

#1


你在线程函数中执行了delete pCalc;
第1个执行到这里的线程把结构给释放了,其它线程得到的数据无法预料。

#2


从代码看没这种问题,应该是你得代码没到点子上

#3


delete pCalc;

delete this;
到底想干什么

#4


怎么可能不能传,处理问题

还有要注意线程同步问题,因为看到了楼主有循环创建线程的代码

#5


1,3楼,他那两delete都没问题得,而且是属于比较正确得处理方法

#6


我试验了一下,也能传进去的,怎么就不可以?

#7


你创建了多个线程。其中有一个线程delete pCalc。该对象已被释放了。

#8


看清楚了,人家delete前已经把所有感兴趣的东西保存好了,后来再也没用那个结构,这样的代码没见过,怀疑你以前都没正确传过结构给线程。上面是比较好的做法之一

#9


他代码没问题,出错另有原因

#10


书上面也是这样说的,删除this是因为我用CreateEx()这个方法创建窗口,书上面面说退出程序的时候要把this给释放掉
我就郁闷我用变量接收结构里面的地址,值都是垃圾的???
是不是应为我用了.net 2008 的原因,
我用VC++6.0在试试

#11


LS可能没注意到,LZ是用一个循环创建多个线程,把new出来的同一个指针传给了每一个线程,在每个线程中都会delete一次,其它就多不说了。

#12


后面我把循环去掉了也不行

#13


问题不是delete this,而是delete pCalc。

#14


11楼的意思是不是要把那个创建结构,放在循环里面?

#15


如果把循环去掉也不行,除非是你相关代码没贴全或者有其它线程破坏了堆中的数据。

#16



#include <AfxWin.h>
#include "resource.h"
#include "ThreadTest.h"


#define IDC_EDIT_MAX 100
#define IDC_EDIT_MIN 101
#define IDC_EDIT_TN  102
#define IDC_EDIT_PO  103
#define IDC_BUTTON_CACL 104
#define IDC_LIST_MESSAGE 105
#define WM_USER_THREAD WM_USER + 0x01

typedef struct tagCALCINFO {
HWND hWnd;
int nMax;
int nMin;
int nThreadNumber;
CCriticalSection* pCs;
}CALCINFO;

CMyApp myApp;

BOOL CMyApp::InitInstance()
{
// TODO: 在此添加专用代码和/或调用基类
m_pMainWnd = new CMainWindow;
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}

CMainWindow::CMainWindow()
{
CString strWndClass = AfxRegisterWndClass(
0,
myApp.LoadStandardCursor(IDC_ARROW),
(HBRUSH)(COLOR_3DFACE + 1),
myApp.LoadStandardIcon(IDI_INFORMATION)
);
CreateEx(0, strWndClass,_T("ThreadTest"),WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,NULL);
CRect rect(0,0,800,600);
CalcWindowRect(&rect);

SetWindowPos(NULL,1000, 400, 300, 420,SWP_NOZORDER|SWP_NOMOVE|SWP_NOREDRAW);
// Create(NULL,_T("ThreadTest"),WS_OVERLAPPEDWINDOW,CRect(500,200,800,600));
}

BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd)
ON_WM_CREATE()
ON_BN_CLICKED(IDC_BUTTON_CACL, OnButtonCacl)
END_MESSAGE_MAP()

int CMainWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;

// TODO:  在此添加您专用的创建代码

if (!m_wndStatic1.Create(_T("累加开始于:"),WS_VISIBLE|WS_CHILD|WS_EX_LEFT|WS_BORDER,
CRect(3,3,70,23),this,IDC_STATIC))
return -1;

if (!m_wndEditMin.Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL|WS_BORDER,
CRect(3,26,203,49),this,IDC_EDIT_MIN))
return -1;
m_wndEditMin.SetWindowText(_T("0"));

if (!m_wndStatic2.Create(_T("累加结束于:"),WS_VISIBLE|WS_CHILD|WS_EX_LEFT|WS_BORDER,
CRect(3,52,70,72),this,IDC_STATIC))
return -1;

if (!m_wndEditMax.Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL|WS_BORDER,
CRect(3,75,203,98),this,IDC_EDIT_MAX))
return -1;
m_wndEditMax.SetWindowText(_T("10000"));

if (!m_wndStatic3.Create(_T("使用线程数量:"),WS_VISIBLE|WS_CHILD|WS_EX_LEFT|WS_BORDER,
CRect(3,101,70,121),this,IDC_STATIC))
return -1;

if(!m_wndEditTN.Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL|WS_BORDER,
CRect(3,124,103,147),this,IDC_EDIT_TN))
return -1;
m_wndEditTN.SetWindowText(_T("2"));

if(!m_wndButtonCacl.Create(_T("开始计算"),WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON|BS_VCENTER|BS_CENTER,
CRect(106,124,206,147),this,IDC_BUTTON_CACL))
return -1;

if(!m_wndStatic5.Create(_T("累加结果:"),WS_VISIBLE|WS_CHILD|WS_EX_LEFT|WS_BORDER,
CRect(3,150,80,173),this,IDC_STATIC))
return -1;

if(!m_wndEditPO.Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL|WS_BORDER,
CRect(3,176,203,199),this,IDC_EDIT_PO))
return -1;

return 0;
}

void CMainWindow::OnButtonCacl()
{
m_wndEditPO.SetWindowText(_T("0"));

m_wndEditMax.GetWindowText(strMax);
m_wndEditMin.GetWindowText(strMin);
m_wndEditTN.GetWindowText(strThreadNumber);

int nMax, nMin, nThreadNumber;
nMax = _ttoi(strMax);
nMin = _ttoi(strMin);
nThreadNumber = _ttoi(strThreadNumber);

m_wndButtonCacl.EnableWindow(FALSE);


for(int i=1; i<=nThreadNumber; i++)
{
CALCINFO* calcinfo = new CALCINFO;
calcinfo->hWnd = m_hWnd;
calcinfo->nMax = nMax;
calcinfo->nMin = nMin;
calcinfo->nThreadNumber = nThreadNumber;
calcinfo->pCs = &m_cs;
AfxBeginThread(ThreadFunc, calcinfo);
}
}

UINT ThreadFunc(LPVOID pPrama)
{
CALCINFO* pCalc = (CALCINFO*)pPrama;
int nMax = pCalc->nMax;
int nMin = pCalc->nMin;
int nThreadNumber = pCalc->nThreadNumber;
HWND hWnd = pCalc->hWnd;
CCriticalSection* pCs = pCalc->pCs;
delete pCalc;
long nStep = (nMax - nMin + 1) / nThreadNumber;
long beginValue = nMin + nStep * (nThreadNumber -1);
long endValue = beginValue + nStep;
long result = 0;
for (long i=beginValue; i<endValue; i++)
{
result += i;
}
pCs->Lock();
long sum = 0;
sum += result;
::PostMessage(hWnd, WM_USER_THREAD, (WPARAM)sum, 0);
pCs->Unlock();
return 0;
}

LRESULT CMainWindow::OnThreadFinished(WPARAM wParam, LPARAM lParam)
{
int nResult = (int)wParam;
CString strResult;
strResult.Format("%d",nResult);
m_wndEditPO.SetWindowText(strResult);
m_wndButtonCacl.EnableWindow(TRUE);
return 0;
}

void CMainWindow::PostNcDestroy()
{
// TODO: 在此添加专用代码和/或调用基类

delete this;
}

#17


修改了一点还是不行

#18


确实,楼主应该每个线程new一个,而不是在循环外new一个然后给每个线程都同一个指针

#19


建议你先这样看一下,在nMax = _ttoi(strMax);和int nMax = pCalc->nMax;之后都加入如下代码:
CString message;
message.Format("%d", nMax);
AfxMessageBox(message);
只用一个线程试一下,看两次输出的结果是否相同。

#20


两边都相等,但是我后面的nResult的值等于0

#21


你这个又没有共享数据,要lock干吗?

至于返回值不对,在Postmessage前加个断点,跟踪一下吧

#22


难道不是有多个线程共享这个值吗?

#23


共享谁了?sum不是你线程内部定义得么?

#24


编译器说我这个hWnd有问题

#25


它怎么说得》?

#26


nResult的值与Max、Min和nThreadNumber的值有关,测试的时候Max给大一些就不是0了,例如:Max=100, min=1, nThreadNumber=3这样试试。
另外你那个sum根本没意义。

#27


如果你想统计所有线程之中得和,sum就不能这么定义,可以考虑定义成那个窗口得一个成员对象,然后在消息处理函数中求和,这样就簿需要锁了

#28


谢谢

#29


+ hWnd 0x00130830 {unused=2228285 } HWND__ *
我把SUM定义为全局变量了,而且用了一个进程锁呀
pCs->Lock();
sum += result;
::PostMessage(hWnd, WM_USER_THREAD, (WPARAM)sum, 0);
pCs->Unlock();

#30


try the following:

step 1:
Add the follwing data members in CMainWindow.hh
private: 
int m_nMax;
int m_nMin;
int m_nThreadNumber;

public:
int getMax(){return m_nMax;}
int getMin(){return m_nMin;}
int getThreadNumber(return m_nThreadNumber;}

step 2:
void CMainWindow::OnButtonCacl()
{
    m_wndEditPO.SetWindowText(_T("0"));    
        
    m_wndEditMax.GetWindowText(strMax);
    m_wndEditMin.GetWindowText(strMin);
    m_wndEditTN.GetWindowText(strThreadNumber);
    
    m_nMax = _ttoi(strMax);
    m_nMin = _ttoi(strMin);
    m_nThreadNumber = _ttoi(strThreadNumber);

    m_wndButtonCacl.EnableWindow(FALSE);
    
    for(int i=1; i<=nThreadNumber; i++)
    {
        AfxBeginThread(ThreadFunc, this);
    }
}

step 3:
UINT ThreadFunc(LPVOID pPrama)
{
    CMainWindow* pData = (CMainWindow*)pPrama;
    int nMax = pData->getMax();
    .
    .
    .
    ::SendMessage(pData->m_hWnd, WM_USER_THREAD, (WPARAM)sum, 0);
    return 0x0;
}

#31


多个线程都在delete pCalc;但是只在他们的父线程中new;

#1


你在线程函数中执行了delete pCalc;
第1个执行到这里的线程把结构给释放了,其它线程得到的数据无法预料。

#2


从代码看没这种问题,应该是你得代码没到点子上

#3


delete pCalc;

delete this;
到底想干什么

#4


怎么可能不能传,处理问题

还有要注意线程同步问题,因为看到了楼主有循环创建线程的代码

#5


1,3楼,他那两delete都没问题得,而且是属于比较正确得处理方法

#6


我试验了一下,也能传进去的,怎么就不可以?

#7


你创建了多个线程。其中有一个线程delete pCalc。该对象已被释放了。

#8


看清楚了,人家delete前已经把所有感兴趣的东西保存好了,后来再也没用那个结构,这样的代码没见过,怀疑你以前都没正确传过结构给线程。上面是比较好的做法之一

#9


他代码没问题,出错另有原因

#10


书上面也是这样说的,删除this是因为我用CreateEx()这个方法创建窗口,书上面面说退出程序的时候要把this给释放掉
我就郁闷我用变量接收结构里面的地址,值都是垃圾的???
是不是应为我用了.net 2008 的原因,
我用VC++6.0在试试

#11


LS可能没注意到,LZ是用一个循环创建多个线程,把new出来的同一个指针传给了每一个线程,在每个线程中都会delete一次,其它就多不说了。

#12


后面我把循环去掉了也不行

#13


问题不是delete this,而是delete pCalc。

#14


11楼的意思是不是要把那个创建结构,放在循环里面?

#15


如果把循环去掉也不行,除非是你相关代码没贴全或者有其它线程破坏了堆中的数据。

#16



#include <AfxWin.h>
#include "resource.h"
#include "ThreadTest.h"


#define IDC_EDIT_MAX 100
#define IDC_EDIT_MIN 101
#define IDC_EDIT_TN  102
#define IDC_EDIT_PO  103
#define IDC_BUTTON_CACL 104
#define IDC_LIST_MESSAGE 105
#define WM_USER_THREAD WM_USER + 0x01

typedef struct tagCALCINFO {
HWND hWnd;
int nMax;
int nMin;
int nThreadNumber;
CCriticalSection* pCs;
}CALCINFO;

CMyApp myApp;

BOOL CMyApp::InitInstance()
{
// TODO: 在此添加专用代码和/或调用基类
m_pMainWnd = new CMainWindow;
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}

CMainWindow::CMainWindow()
{
CString strWndClass = AfxRegisterWndClass(
0,
myApp.LoadStandardCursor(IDC_ARROW),
(HBRUSH)(COLOR_3DFACE + 1),
myApp.LoadStandardIcon(IDI_INFORMATION)
);
CreateEx(0, strWndClass,_T("ThreadTest"),WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,NULL);
CRect rect(0,0,800,600);
CalcWindowRect(&rect);

SetWindowPos(NULL,1000, 400, 300, 420,SWP_NOZORDER|SWP_NOMOVE|SWP_NOREDRAW);
// Create(NULL,_T("ThreadTest"),WS_OVERLAPPEDWINDOW,CRect(500,200,800,600));
}

BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd)
ON_WM_CREATE()
ON_BN_CLICKED(IDC_BUTTON_CACL, OnButtonCacl)
END_MESSAGE_MAP()

int CMainWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;

// TODO:  在此添加您专用的创建代码

if (!m_wndStatic1.Create(_T("累加开始于:"),WS_VISIBLE|WS_CHILD|WS_EX_LEFT|WS_BORDER,
CRect(3,3,70,23),this,IDC_STATIC))
return -1;

if (!m_wndEditMin.Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL|WS_BORDER,
CRect(3,26,203,49),this,IDC_EDIT_MIN))
return -1;
m_wndEditMin.SetWindowText(_T("0"));

if (!m_wndStatic2.Create(_T("累加结束于:"),WS_VISIBLE|WS_CHILD|WS_EX_LEFT|WS_BORDER,
CRect(3,52,70,72),this,IDC_STATIC))
return -1;

if (!m_wndEditMax.Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL|WS_BORDER,
CRect(3,75,203,98),this,IDC_EDIT_MAX))
return -1;
m_wndEditMax.SetWindowText(_T("10000"));

if (!m_wndStatic3.Create(_T("使用线程数量:"),WS_VISIBLE|WS_CHILD|WS_EX_LEFT|WS_BORDER,
CRect(3,101,70,121),this,IDC_STATIC))
return -1;

if(!m_wndEditTN.Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL|WS_BORDER,
CRect(3,124,103,147),this,IDC_EDIT_TN))
return -1;
m_wndEditTN.SetWindowText(_T("2"));

if(!m_wndButtonCacl.Create(_T("开始计算"),WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON|BS_VCENTER|BS_CENTER,
CRect(106,124,206,147),this,IDC_BUTTON_CACL))
return -1;

if(!m_wndStatic5.Create(_T("累加结果:"),WS_VISIBLE|WS_CHILD|WS_EX_LEFT|WS_BORDER,
CRect(3,150,80,173),this,IDC_STATIC))
return -1;

if(!m_wndEditPO.Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL|WS_BORDER,
CRect(3,176,203,199),this,IDC_EDIT_PO))
return -1;

return 0;
}

void CMainWindow::OnButtonCacl()
{
m_wndEditPO.SetWindowText(_T("0"));

m_wndEditMax.GetWindowText(strMax);
m_wndEditMin.GetWindowText(strMin);
m_wndEditTN.GetWindowText(strThreadNumber);

int nMax, nMin, nThreadNumber;
nMax = _ttoi(strMax);
nMin = _ttoi(strMin);
nThreadNumber = _ttoi(strThreadNumber);

m_wndButtonCacl.EnableWindow(FALSE);


for(int i=1; i<=nThreadNumber; i++)
{
CALCINFO* calcinfo = new CALCINFO;
calcinfo->hWnd = m_hWnd;
calcinfo->nMax = nMax;
calcinfo->nMin = nMin;
calcinfo->nThreadNumber = nThreadNumber;
calcinfo->pCs = &m_cs;
AfxBeginThread(ThreadFunc, calcinfo);
}
}

UINT ThreadFunc(LPVOID pPrama)
{
CALCINFO* pCalc = (CALCINFO*)pPrama;
int nMax = pCalc->nMax;
int nMin = pCalc->nMin;
int nThreadNumber = pCalc->nThreadNumber;
HWND hWnd = pCalc->hWnd;
CCriticalSection* pCs = pCalc->pCs;
delete pCalc;
long nStep = (nMax - nMin + 1) / nThreadNumber;
long beginValue = nMin + nStep * (nThreadNumber -1);
long endValue = beginValue + nStep;
long result = 0;
for (long i=beginValue; i<endValue; i++)
{
result += i;
}
pCs->Lock();
long sum = 0;
sum += result;
::PostMessage(hWnd, WM_USER_THREAD, (WPARAM)sum, 0);
pCs->Unlock();
return 0;
}

LRESULT CMainWindow::OnThreadFinished(WPARAM wParam, LPARAM lParam)
{
int nResult = (int)wParam;
CString strResult;
strResult.Format("%d",nResult);
m_wndEditPO.SetWindowText(strResult);
m_wndButtonCacl.EnableWindow(TRUE);
return 0;
}

void CMainWindow::PostNcDestroy()
{
// TODO: 在此添加专用代码和/或调用基类

delete this;
}

#17


修改了一点还是不行

#18


确实,楼主应该每个线程new一个,而不是在循环外new一个然后给每个线程都同一个指针

#19


建议你先这样看一下,在nMax = _ttoi(strMax);和int nMax = pCalc->nMax;之后都加入如下代码:
CString message;
message.Format("%d", nMax);
AfxMessageBox(message);
只用一个线程试一下,看两次输出的结果是否相同。

#20


两边都相等,但是我后面的nResult的值等于0

#21


你这个又没有共享数据,要lock干吗?

至于返回值不对,在Postmessage前加个断点,跟踪一下吧

#22


难道不是有多个线程共享这个值吗?

#23


共享谁了?sum不是你线程内部定义得么?

#24


编译器说我这个hWnd有问题

#25


它怎么说得》?

#26


nResult的值与Max、Min和nThreadNumber的值有关,测试的时候Max给大一些就不是0了,例如:Max=100, min=1, nThreadNumber=3这样试试。
另外你那个sum根本没意义。

#27


如果你想统计所有线程之中得和,sum就不能这么定义,可以考虑定义成那个窗口得一个成员对象,然后在消息处理函数中求和,这样就簿需要锁了

#28


谢谢

#29


+ hWnd 0x00130830 {unused=2228285 } HWND__ *
我把SUM定义为全局变量了,而且用了一个进程锁呀
pCs->Lock();
sum += result;
::PostMessage(hWnd, WM_USER_THREAD, (WPARAM)sum, 0);
pCs->Unlock();

#30


try the following:

step 1:
Add the follwing data members in CMainWindow.hh
private: 
int m_nMax;
int m_nMin;
int m_nThreadNumber;

public:
int getMax(){return m_nMax;}
int getMin(){return m_nMin;}
int getThreadNumber(return m_nThreadNumber;}

step 2:
void CMainWindow::OnButtonCacl()
{
    m_wndEditPO.SetWindowText(_T("0"));    
        
    m_wndEditMax.GetWindowText(strMax);
    m_wndEditMin.GetWindowText(strMin);
    m_wndEditTN.GetWindowText(strThreadNumber);
    
    m_nMax = _ttoi(strMax);
    m_nMin = _ttoi(strMin);
    m_nThreadNumber = _ttoi(strThreadNumber);

    m_wndButtonCacl.EnableWindow(FALSE);
    
    for(int i=1; i<=nThreadNumber; i++)
    {
        AfxBeginThread(ThreadFunc, this);
    }
}

step 3:
UINT ThreadFunc(LPVOID pPrama)
{
    CMainWindow* pData = (CMainWindow*)pPrama;
    int nMax = pData->getMax();
    .
    .
    .
    ::SendMessage(pData->m_hWnd, WM_USER_THREAD, (WPARAM)sum, 0);
    return 0x0;
}

#31


多个线程都在delete pCalc;但是只在他们的父线程中new;