_beginthreadex线程安全问题

merry_wanwan 2011-09-27 01:29:32




class testClass
{
public:
testClass();
testClass(testClass & test);
string param1;
string param2;
}

//默认构造
testClass::testClass():param1("hi"), param("hello")
{}

//复制构造
testClass::testClass(testClass & test)
{
param1 = test.param1;
param2 = test.param2;
}

//这个函数开启线程
void CallThread( testClass param )
{
HANDLE hThread;
unsigned threadId;
hThread = _beginthread(NULL, 0, ThreadWork, ¶m, 0, &threadId);
}

//线程执行函数
unsigned __stdcall ThreadWork(void * param)
{
//在这里取出传进来的值
testClass test = *((testClass*)param);
//这里再做许多的事情,也许会很久
}


当CallThread创建进程之后,函数会释放param ,导致线程中取值为野指针。
好像“线程传参”只能传递指针,不能复制传递。
请教各位如何解决这个问题,先谢谢。(代码是直接在这里手打的,也许有点问题)



...全文
155 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
merry_wanwan 2011-09-27
  • 打赏
  • 举报
回复
好吧,用一个比较挫的方法
在线程外面new,线程里面delete。但是如果忘记释放了就泄露了。
merry_wanwan 2011-09-27
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 peige2008 的回复:]

引用 14 楼 merry_wanwan 的回复:

引用 13 楼 peige2008 的回复:

你原来的代码加个sleep就可以运行了。
至于你信不信,由你,我反正是信了~

这个应该是有隐患的
例如sleep(1000);
如果线程中在这1000ms之后,再去读取这个变量,则出错

但是如果进入线程马上取出来保存,是可以的。(隐患在于:如果在1000ms内,该线程还……
[/Quote]
这个方法和全局其实是一样的,如果在取值之前,变量被释放,或者全局变量被再次调用覆盖,还是会出问题。。难道架构设计得不合理吗
merry_wanwan 2011-09-27
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 captainlee007 的回复:]
void CallThread( testClass *param )
[/Quote]

//例如这样
void CallThread( testClass * param );
main()
{
while(1)
{
testClass * param = GetTestClass();
CallThread(param );
}
}


也是会释放啊
PG 2011-09-27
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 merry_wanwan 的回复:]

引用 13 楼 peige2008 的回复:

你原来的代码加个sleep就可以运行了。
至于你信不信,由你,我反正是信了~

这个应该是有隐患的
例如sleep(1000);
如果线程中在这1000ms之后,再去读取这个变量,则出错

但是如果进入线程马上取出来保存,是可以的。(隐患在于:如果在1000ms内,该线程还没有启动呢?)
[/Quote]
那就5秒~
captainlee007 2011-09-27
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 merry_wanwan 的回复:]

引用 3 楼 namelij 的回复:
testClass *test = (testClass*)param;
用指针吧,我最开始也犯过你这样的错误



是这样吗?
C/C++ code

//线程执行函数
unsigned __stdcall ThreadWork(void * param)
{
//在这里取出传进来的值
testClass * test = (……
[/Quote]

void CallThread( testClass *param )
merry_wanwan 2011-09-27
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 peige2008 的回复:]

你原来的代码加个sleep就可以运行了。
至于你信不信,由你,我反正是信了~
[/Quote]
这个应该是有隐患的
例如sleep(1000);
如果线程中在这1000ms之后,再去读取这个变量,则出错

但是如果进入线程马上取出来保存,是可以的。(隐患在于:如果在1000ms内,该线程还没有启动呢?)
PG 2011-09-27
  • 打赏
  • 举报
回复
你原来的代码加个sleep就可以运行了。
至于你信不信,由你,我反正是信了~
merry_wanwan 2011-09-27
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 peige2008 的回复:]
testClass test = *((testClass*)param);
你这个东西能取出来就可以了^ ^!!!
[/Quote]
如果waitFOrSingleOBject,会导致上层没有释放,可以取的,但是程序流程不允许使用waitFOrSingleOBject....

[Quote=引用 11 楼 guanyijun123 的回复:]
如果你是个全局变变量或成员函数,只要程序不挂就不会有问题!
[/Quote]
全局不会释放。成员函数?这个没有看懂,可以解释下吗?
迷途的书童 2011-09-27
  • 打赏
  • 举报
回复
如果你是个全局变变量或成员函数,只要程序不挂就不会有问题!
PG 2011-09-27
  • 打赏
  • 举报
回复
testClass test = *((testClass*)param);
你这个东西能取出来就可以了^ ^!!!
merry_wanwan 2011-09-27
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 peige2008 的回复:]
在hThread = _beginthread(NULL, 0, ThreadWork, &param, 0, &threadId);
后面sleep(1000)吧;
[/Quote]
100也许做不完,如果waitFOrSingleOBject也不行,因为要多线程循环接受任务
PG 2011-09-27
  • 打赏
  • 举报
回复
在hThread = _beginthread(NULL, 0, ThreadWork, ¶m, 0, &threadId);
后面sleep(1000)吧;
merry_wanwan 2011-09-27
  • 打赏
  • 举报
回复
都是局部的,没有全局变量
有没有不用全局可以解决的方法呢?
bdmh 2011-09-27
  • 打赏
  • 举报
回复
看看你具体怎么用的,是全局指针还是局部指针
PG 2011-09-27
  • 打赏
  • 举报
回复
顶~~
merry_wanwan 2011-09-27
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 namelij 的回复:]
testClass *test = (testClass*)param;
用指针吧,我最开始也犯过你这样的错误
[/Quote]


是这样吗?

//线程执行函数
unsigned __stdcall ThreadWork(void * param)
{
//在这里取出传进来的值
testClass * test = (testClass*)param;
//这里再做许多的事情,也许会很久
}

测试了一下,还是野指针。
个人觉得,如果传的是指针,当原始指针释放的时候,还是会野吧?
或者是如果有指针在使用这个地址就不会释放?(好像没在书上看到过。。)
  • 打赏
  • 举报
回复
testClass *test = (testClass*)param;
用指针吧,我最开始也犯过你这样的错误
merry_wanwan 2011-09-27
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 bdmh 的回复:]
传testClass * 或testClass &,否则 会创建一个,然后释放
[/Quote]

bdmh的意思是这样吗?
void CallThread( testClass * param )
void CallThread( testClass & param )


//例如这样
void CallThread( testClass & param );
main()
{
while(1)
{
testClass param = GetTestClass();
CallThread(param );
}
}

这样也会由于上层调用的释放而变成野指针吧?
bdmh 2011-09-27
  • 打赏
  • 举报
回复
传testClass * 或testClass &,否则 会创建一个,然后释放
仿多线程的效果一般有2种办法:第一种是通过定时器;第二种是启动多线程,不同模式下启动函数不同,mfc与API与WIN32下面注意点也是有区别的! VC启动一个新线程的三种方法,有需要的朋友可以参考下。 第一种AfxBeginThread() 用AfxBeginThread()函数来创建一个新线程来执行任务,工作者线程的AfxBeginThread的原型如下: CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,   LPVOID lParam,   int nPriority = THREAD_PRIORITY_NORMAL,   UINT nStackSize = 0,   DWORD dwCreateFlags = 0,   LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL   );//用于创建工作者线程 返回值: 成功时返回一个指向新线程的线程对象的指针,否则NULL。 pfnThreadProc : 线程的入口函数,声明一定要如下: UINT MyThreadFunction(LPVOID pParam),不能设置为NULL; pParam : 传递入线程的参数,注意它的类型为:LPVOID,所以我们可以传递一个结构体入线程. nPriority : 线程的优先级,一般设置为 0 .让它和主线程具有共同的优先级. nStackSize : 指定新创建的线程的栈的大小.如果为 0,新创建的线程具有和主线程一样的大小的栈 dwCreateFlags : 指定创建线程以后,线程有怎么样的标志.可以指定两个值: CREATE_SUSPENDED : 线程创建以后,会处于挂起状态,直到调用:ResumeThread 0 : 创建线程后就开始运行. lpSecurityAttrs : 指向一个 SECURITY_ATTRIBUTES 的结构体,用它来标志新创建线程的安全性.如果为 NULL, 那么新创建的线程就具有和主线程一样的安全性. 如果要在线程内结束线程,可以在线程内调用 AfxEndThread. 一般直接用AfxBeginThread(ThreadProc,this); 示例: UINT myproc(LPVOID lParam){CITTDlg *pWnd = (CITTDlg *)lParam; //将窗口指针赋给无类型指针pWnd->KMeansSegment(); //要执行的函数return 1;}void CITTDlg::KMeansSegment(){// 主要处理函数在这里写}void CITTDlg::OnKMeansSegment() //按钮点击执行{AfxBeginThread(myproc, (LPVOID)this);//启动新的线程} 注意,工作者线程的函数必须是全局函数或静态成员函数,不能是普通的成员函数。 第二种CreateThread()函数原型为:HANDLECreateThread( NULL, // 没有安全描述符 0, // 默认线程栈的大小 MyThreadProc, // 线程函数指针,即函数名 (LPVOID)&n, // 传递参数 NULL, // 没有附加属性 NULL // 不需要获得线程号码 ); CreatThread,它返回的是一个句柄;如果不需要再监视线程,则用CloseHandle()关闭线程句柄。 线程的函数必须定义为: DWORD WINAPI MyThreadProc(LPVOID pParameter); 下面演示多线程操作控件,点击一个Button然后运行一个线程,将字符串显示在CEdit控件里面; 示例: .h头文件struct hS {CString Tmp;CTestDlg *hWnd; };//定义全局结构体,用来传递自定义消息DWORD WINAPI ThreadProc(LPVOIDlpParam);//线程函数声明,全局函数public: CString chtmp; struct hS *hTmp;protected: HANDLE m_hThread;//线程句柄 CEdit m_Edit;.cpp实现文件//线程执行函数DWORD WINAPI ThreadProc(LPVOID lpParam){//在这里写处理函数struct hS *Tmp2;Tmp2 = (hS*)lpParam;// 操作: Tmp2->hWnd->m_Edit.SetWindowText( (LPTSTR)Tmp2->Tmp );}void CTestDlg::OnBnClickedButton1(){ hTmp->Tmp = chtmp; hTmp->hWnd = this;//关键是把this指针传进去 m_hThread =CreateThread(NULL,0,ThreadProc,hTmp,0,NULL);//创建新线程 CloseHandle(m_hThread );} 用CreateThread()函数创建线程将返回一个线程句柄,通过该句柄你可以控制和操作该线程,当你不用时可以一创建该线程后就关闭该句柄,有专门的函CloseHandle()。关闭句柄不代表关闭线程,只是你不能在外部控制该线程(比如,提前结束,更改优先级等)。在线程结束后,系统将自动清理线程资源,但并不自动关闭该句柄,所以线程结束后要记得关闭该句柄。 第三种_beginthread() 函数原型为:intptr_t _beginthread( void( *start_address )( void * ), //指向新线程调用的函数的起始地址 unsigned stack_size, //堆栈大小,设置0为系统默认值 void *arglist //传递给线程函数的参数,没有则为NULL ); 返回值: 假如成功,函数将会返回一个新线程的句柄,用户可以像这样声明一个句柄变量存储返回值:   HANDLE hStdOut = _beginthread( CheckKey, 0, NULL )。如果失败_beginthread将返回-1。所在库文件: #include 线程函数的定义: 对于_beginthread()创建的线程,其线程函数定义为: void ThreadPro(void * pArguments ); _beginthreadex()为_beginthread()的升级版。 总结:AfxBeginThread是MFC的全局函数,是对CreateThread的封装。 CreateThread是Win32 API函数,AfxBeginThread最终要调到CreateThread。而_beginthread是C的运行库函数。

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧