工作者线程相关问题一问

littleme741 2001-07-09 07:37:26
在工作者线程中,一般会传进来一个参数。比如
UINT mythreadProc(LPVOID myInfo)
这个myInfo一般是在主线程中分配空间的。有两中方法:

一种是采用new方法,在heap中开辟一块空间,然后传给子线程,子线程(即工作者线程)完工后,释放(delete)这块空间。但问题是:如果我这时候,直接关闭程序的话,这个内存实际上并没有得到释放(因为线程被强行关闭了),需要操作系统在对进程做善后处理才能完成该内存的释放,而我想自己完整控制对内存的释放。这样的话,采用什么方法好呢?当然,我可以在关闭系统的时候,等待所有的线程自然结束以后,在关闭整个进程,但这样的缺点是我要等,但一般“我”(是实际的用户)是不愿意等的。当然可以采用EVENT进行同步,通过激发事件,告诉工作者线程,你快结束,释放相关空间,因为我要退出了,但是还有问题,比如我在主线程中可以产生该工作者线程N次,但我如何为每一个工作者线程设置一个同步对象呢?(因为工作者线程只是一个函数而已,而不是C++对象),还是一个同步对象可以为所有的工作者线程使用呢?这个需要高手指点。

第二种就是采用局部变量(也就是在stack)中分配一个myInfo,然后传给子线程,但这有一个问题就是,当该调用工作者线程的局部函数退出后,会释放该局部变量(myInfo),那么说还是需要在工作者线程那边把个myInfo拷贝一份,这样还是会涉及到释放问题,尤其是如果myInfo结构中包含一些Handle对象的话。

大家在具体编程的时候,是如何解决我提到的这个问题的呢?请指教。
...全文
168 点赞 收藏 21
写回复
21 条回复
littleme741 2001年07月10日
同意AriDo的观点,程序员就是要做即使非常小的概率但是还是会发生的事情。
回复 点赞
AriDo 2001年07月10日
我觉得做程序还是应该有个严谨的态度,有时候程序并不是因为人为的关闭也许你程序中有其他线程的事件或消息触发要去关闭一个线程,按照现在的处理器处理速度也许并不需要你所说的几百或几时毫秒。
回复 点赞
lpt 2001年07月10日
每个线程里都设一个事件,然后在主线程中触发事件,再等待指定时间,倘还没有退回,杀。
这就是我的一般做法,在写了这么多的程序中,好像还没有出现过什么大的问题,上面的一位
兄弟说在起动线时分配的内存会因还没来的及启动线程,会造成内存泄漏,我想就是你一辈子
去做这个实验都不会碰到这种情况的,因为即使你关程序关的再快,它的也要几十毫秒或几百毫
秒吧!而线程启动绝对不要这么长的时间的,所以说,哈哈,不要担心的事,就不要去操心了,
还是去多多关心一下线程怎么最快响应退出消息吧,祝你们好运。
回复 点赞
AriDo 2001年07月10日
听说工作者线程是没有消息循环的是这样吗?那么你给一个工作线程发消息他可以接收到吗?我觉得用公用变量作为线程退出的标志是挺方便的,就是别在线程处理函数中改变公用变量就行了。用事件的方式更有优势吧,你可以使用WaitForSingleObject函数使线程挂起,而不占用CPU循环,而且据说因为事件是内核对象还可以在进程之间进行同步。
回复 点赞
threads 2001年07月10日
从效率上来讲,很明显用全局变量高啊。
回复 点赞
plato 2001年07月10日
这样是绝对不安全的。
void Doit()
{
struct Para para;
CreateThread(..., ¶);
}

一定要:
void Doit()
{
struct Para * para ;
CreateThread(..., para);
}

或者
struct Para para;
void Doit()
{
CreateThread(..., ¶);
}

回复 点赞
flagfly 2001年07月10日
我觉得还是用局部变量。调用工作者线程的局部函数中用局部变量还是new无所谓。进入工作者线程后立即把该变量拷贝到局部变量中,这是就象对待一般函数中的局部变量一样了。剩下的问题其实就是如何用主线程控制子线程的结束的问题了。如果能保证主线程退出时它正常结束所有子线程,则没有泄露问题。
回复 点赞
zhao_ivan 2001年07月10日
plato(天天)说的对,我也是用线程内的局部变量记录下LPVOID后就将NEW 产生的堆DELETE掉。
一般是不会出错的。
回复 点赞
blue_teeth 2001年07月10日
go on!
i like it!
回复 点赞
plato 2001年07月10日
g_bQuit简单一些,在这个例子中,WaitForSingleObject(killEvent)没什么优点。
回复 点赞
littleme741 2001年07月10日
都有一些道理。只不过你们谁可以谈谈在线程中用全局变量和事件作为退出标志的优缺点?
比如如下:
....
for(i=0;i<N;i++)
{
.....
if(g_bQuit)
break;
....
}
也可以是:
....
for(i=0;i<N;i++)
{
.....
if(WaitForSingleObject(killEvent,0)==WAIT_OBJECT_0)
break;
}
这两种各有什么优缺点呢?

另外,你们哪一个对线程池操作有研究,可以一起分析一下,如何?
回复 点赞
zb_china 2001年07月10日
你可以在主线程里用链表管理子线程数据,这样每个子线程都有自己的专用数据。
回复 点赞
plato 2001年07月10日
那你先对每个线程PostThreadMessage( WM_QUIT ),比同步对象简单多了。
然后再WaitForMultiObjects。
回复 点赞
azuo_lee 2001年07月10日
其实在使用全局变量“结束标志”的情况下,上述的全局变量“线程计数”也完全可以不用。在主线程结束时可以先点亮结束标志,然后用WaitForMultipleObjects即可。这样做也省去了自己写代码处理超时的麻烦。但有一个缺点就是你必须在程序中维持一个线程句柄的列表,并随着线程的启动与终止不断更新。
回复 点赞
azuo_lee 2001年07月10日
首先设一个全局变量做线程计数,初始化时该变量为0;以后每个线程进入时对此值加1,退出时减一。另外再设一个全局变量做结束标志,初始化时为假;每个线程在内部不停监测这一标志,当为真时就退出。主线程结束时,首先点亮结束标志(令其为真),然后循环监测线程计数(当然,这里还可引入一些超时机制,以防万一),直至它为0时方可退出。
由于对线程计数的访问必须是互斥的(各个线程都会对其读写),你可以在每个线程对其加减操作时使用互斥对象(Mutex)来实现。结束标志不存在冲突问题(各个线程都是读,只有主线程写),没有必要使用额外的技术。
回复 点赞
littleme741 2001年07月09日
To plato(天天):
你的WaitForMultiObjects(100, threads, TRUE, INFINITE); 确实能等到100个子线程都结束,但是问题是,用户要关闭一个进程,居然要等很长时间(如果该100个子线程非常慢的话),这是不可忍受的。
所以还是要给那100个线程发送一个同步事件(event),告诉它们,你们可以退出循环或者当前的过程,赶快返回。这样是否每一个工作者线程都需要一个同步HANDLE了呢?(这个EVENT HANDLE实际上是由主线程发送给工作者线程的),所以我想每一个工作者线程还是需要一个同步HANDLE的(那样的话,不就是说N个子线程需要N个同步HANDLE对象么?),不知道兄台有什么观点?请指教。
回复 点赞
plato 2001年07月09日
HANDLE threads[100];

threads[0] = CreateThread(...);
threads[1] = CreateThread(...);
......

WaitForMultiObject( 100, threads, TRUE, INFINITE);
回复 点赞
plato 2001年07月09日
用new,线程进去就Copy内存到局部变量,然后马上delete,这样在99.99999%的情况下TerminateThread都不会造成问题。如果实在要追求完美,就用你所说的用Event来等待。

至于如何为每一个工作者线程设置一个同步对象呢?我想没有必要吧?
WaitForMultiObject的参数可以是一个线程句炳的数组,不需要用其他的同步对象了。

另外,TerminateThread,不光造成new的内存不释放,还有分配的其他系统资源也不会释放的。

回复 点赞
littleme741 2001年07月09日
我希望传给每一个mythreadProc的结构都是不一样的。
回复 点赞
littleme741 2001年07月09日
to zb_china(已经离开):
比如这样:
for(i=0;i<100;i++)
{
....
AfxBeginThread(mythreadProc,(LPVOID)&myInfo);
....
}
如果这里的myInfo是全局变量的话,你在第i+1个的线程中改变了myInfo的值,对前面的i个线程就会产生影响。这当然是我所不希望的。

回复 点赞
发动态
发帖子
进程/线程/DLL
创建于2007-09-28

6376

社区成员

4.9w+

社区内容

VC/MFC 进程/线程/DLL
社区公告
暂无公告