多线程的问题???(在线等待)
我想写一个多线程的 下载程序
1。一个全局的函数 UINT DownLoadFunction(LPVOID lParam)
2。一个下载线程类 DownloadThead
AfxBeginThread(::DownLoadFunction, this);
while (thread_finished_flag == FALSE){ }
在构造函数中就启动 线程
3。在主程序中 生成多个 DownloadThead 类。
可程序 好象 就只有一个 线程在运行, 在运行时, 我不能关闭程序,连拖动都不行,只有强行关闭(任务管理器),如果是多线程,我完全可以终止程序。
请高手指点!!!
问题点数:100、回复次数:60Top
1 楼everandforever(Forever)回复于 2002-10-04 16:08:16 得分 10
??你的主线程进无限循环了吧?Top
2 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 16:14:46 得分 0
主线程中
for(int i=0; i<stringArray.GetSize(); i++ ){
fileInfo = (CStringArray *)stringArray.GetAt(i);
DownloadThead dThead(down,fileInfo->GetAt(0),path+fileInfo->GetAt(1));
}
其中 down 是一个专门负责下载的类,
fileInfo->GetAt(0) ,path+fileInfo->GetAt(1)
是一些参数(现在的URL,本地路径)
可以直接 用down(fileInfo->GetAt(0) ,path+fileInfo->GetAt(1));
来完成下载,但这只是但线程的。
请指教!!!
Top
3 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 16:15:18 得分 0
主线程中
for(int i=0; i<stringArray.GetSize(); i++ ){
fileInfo = (CStringArray *)stringArray.GetAt(i);
DownloadThead dThead(down,fileInfo->GetAt(0),path+fileInfo->GetAt(1));
}
其中 down 是一个专门负责下载的类,
fileInfo->GetAt(0) ,path+fileInfo->GetAt(1)
是一些参数(现在的URL,本地路径)
可以直接 用down(fileInfo->GetAt(0) ,path+fileInfo->GetAt(1));
来完成下载,但这只是但线程的。
请指教!!!
Top
4 楼everandforever(Forever)回复于 2002-10-04 16:18:00 得分 4
DownloadThead(down,fileInfo->GetAt(0),path+fileInfo->GetAt(1));
这个函数是启动子线程的?Top
5 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 16:19:58 得分 0
对,
DownloadThead::DownloadThead(CHttpDownload down, CString downloadUrl,CString savePath)
{
thread_finished_flag = FALSE;
this->downloadUrl = downloadUrl;
this->savePath = savePath;
this->down = down;
CWinThread *ct = AfxBeginThread(::DownLoadFunction, this);
while (thread_finished_flag == FALSE){
}
}Top
6 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 16:20:50 得分 0
DownloadThead * pDownI = (DownloadThead *)lParam;
if (pDownI == NULL){
pDownI->thread_finished_flag = TRUE;
return -1;
}
pDownI->down.Download( pDownI->downloadUrl , pDownI->savePath);
pDownI->thread_finished_flag = TRUE;
return 0;Top
7 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 16:21:28 得分 0
以上是
UINT DownLoadFunction(LPVOID lParam)
{
DownloadThead * pDownI = (DownloadThead *)lParam;
if (pDownI == NULL){
pDownI->thread_finished_flag = TRUE;
return -1;
}
pDownI->down.Download( pDownI->downloadUrl , pDownI->savePath);
pDownI->thread_finished_flag = TRUE;
return 0;
}Top
8 楼everandforever(Forever)回复于 2002-10-04 16:21:48 得分 2
while (thread_finished_flag == FALSE){
}
到了这一句,主线程就进无限循环了,怎么创建下一个线程?Top
9 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 16:23:39 得分 0
那我该怎么办呢?
谢了Top
10 楼everandforever(Forever)回复于 2002-10-04 16:25:10 得分 2
你主线程为什么要 thread_finished_flag == FALSE 等待这个子线程完成?
如果不是必须的话,你可以去掉
while (thread_finished_flag == FALSE){
}
这一句.Top
11 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 16:27:03 得分 0
但我去掉后好象 线程还没执行完,就终止了Top
12 楼LoveTide(say no to ISO-8859-1、CVS)回复于 2002-10-04 16:27:19 得分 2
thread结束后 post 给主thread一个TheadTerminated 的消息都好过 你在这里while循环...Top
13 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 16:28:51 得分 0
可以具体点吗?
Top
14 楼everandforever(Forever)回复于 2002-10-04 16:29:52 得分 2
DownloadThead dThead(down,fileInfo->GetAt(0),path+fileInfo->GetAt(1));
大约是局部变量 DTHREAD 被销毁了. 你用NEW创建DTHREAD试试Top
15 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 16:30:45 得分 0
我该怎么
PostMessage
到主thread
BOOL PostMessage(
HWND hWnd, // handle of destination window
UINT Msg, // message to post
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
Top
16 楼everandforever(Forever)回复于 2002-10-04 16:31:26 得分 2
for(int i=0; i<stringArray.GetSize(); i++ ){
fileInfo = (CStringArray *)stringArray.GetAt(i);
new DownloadThead(down,fileInfo->GetAt(0),path+fileInfo->GetAt(1));
}Top
17 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 16:31:38 得分 0
好,我先试试
Top
18 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 16:38:12 得分 0
有2个问题:
1。线程退出时提示(没有运行完): Detected memory leaks!
2。仍然不能拖动!
:(
请在指教Top
19 楼caitou123(自向红尘取烦恼)回复于 2002-10-04 16:52:47 得分 2
为什么不用CreatEvent生成i个事件变量,在子线程设置事件变量,在主线程中用WaitForMultipObjectcs来等待子线程完成。
你删去了死循环后,主线程线先结束了而导致子线程被终止。Top
20 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 16:58:25 得分 0
TO:caitou123(自向红尘取烦恼)
具体点好吗?
:(((((Top
21 楼LoveTide(say no to ISO-8859-1、CVS)回复于 2002-10-04 17:00:09 得分 2
PostThreadMessage...
>我该怎么
>PostMessage
>到主thread
Top
22 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 17:08:17 得分 0
BOOL PostThreadMessage(
DWORD idThread, // thread identifier
UINT Msg, // message to post
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
那 idThread 是什么?
Msg 是什么?
由于对vc 是菜鸟
多指点Top
23 楼LoveTide(say no to ISO-8859-1、CVS)回复于 2002-10-04 17:15:35 得分 10
DWORD idThread: 每一个CWinThread都有一个ID,呵呵...
UINT Msg: 你想要Post的消息,呵呵...
UINT DownLoadFunction(LPVOID lParam)
{
DownloadThead * pDownI = (DownloadThead *)lParam;
if (pDownI == NULL){
pDownI->thread_finished_flag = TRUE;
return -1;
}
pDownI->down.Download( pDownI->downloadUrl , pDownI->savePath);
//pDownI->thread_finished_flag = TRUE;
PostThreadMessage (theApp.m_nThreadID, 线程结束消息, 0, GetCurrentThreadId()); //呵呵
return 0;
}
Top
24 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 17:18:59 得分 0
TO:
LoveTide(一个月挣多少钱知足?)
"线程结束消息"
是不是我定义一个 常量(还是已经有的)
那在主线程中要做相应的处理代码吗?(还是系统自己处理)Top
25 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 17:22:36 得分 0
是不是 WM_QUITTop
26 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 17:26:42 得分 0
E:\project\Éý¼¶Èí¼þ\¸´¼þ Éý¼¶Ä£¿é\DownloadThead.cpp(63) : error C2065: 'theApp' : undeclared identifier
E:\project\Éý¼¶Èí¼þ\¸´¼þ Éý¼¶Ä£¿é\DownloadThead.cpp(63) : error C2228: left of '.m_nThreadID' must have class/struct/union type
UINT DownLoadFunction(LPVOID lParam) 是全局函数 出现错误
Top
27 楼tjq_tang(过河兵)回复于 2002-10-04 17:36:33 得分 2
up
Top
28 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 17:37:02 得分 0
PostThreadMessage (theApp.m_nThreadID, WM_QUIT
, 0, GetCurrentThreadId()); //呵呵
一运行 就退出Top
29 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 17:57:57 得分 0
我定义了一个常量
但我在
DownloadThead::DownloadThead(CHttpDownload down, CString downloadUrl,CString savePath)
{
thread_finished_flag = FALSE;
this->downloadUrl = downloadUrl;
this->savePath = savePath;
this->down = down;
CWinThread *ct = AfxBeginThread(::DownLoadFunction, this);
//while (thread_finished_flag == FALSE){}
// ????????
}
该怎么处理呢???
Top
30 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-04 18:16:14 得分 0
我在 DownloadThead::DownloadThead(CHttpDownload down, CString downloadUrl,CString savePath) 加入
MSG msg;
while( ::GetMessage( &msg, NULL, 0, 0 ) )
{
if( msg.message == WM_THERD_END )
break;
else
::DispatchMessage( &msg );
}
还是不行,请大虾在指点!!!!
Top
31 楼tleon(澎蜞)回复于 2002-10-04 18:17:32 得分 2
建议使用WaitForSingleObject等待信号量,而不是while
推荐一本好书,好象叫《win32多线程....》Top
32 楼caitou123(自向红尘取烦恼)回复于 2002-10-04 18:48:55 得分 2
DownloadThead::DownloadThead(CHttpDownload down, CString downloadUrl,CString savePath)
{
thread_finished_flag = FALSE;
this->downloadUrl = downloadUrl;
this->savePath = savePath;
this->down = down;
CWinThread *ct = AfxBeginThread(::DownLoadFunction, this);
//////////////////////
static i=0; //你的线程数
// HANDLE thread[4];
thread[i++]=ct->m_hThread
//while (thread_finished_flag == FALSE){}
// ????????
}
主线程中
HANDLE thread[stringArray.GetSize()]; //你的线程数
...
WaitForMultipObjects(stringArray.GetSize(),thread,TRUE,INFINITE);
//while (thread_finished_flag == FALSE){
//}
Top
33 楼wacky(笨笨狗)回复于 2002-10-04 19:59:55 得分 2
在你的子线程中定义三个HANDLE信号变量与临界区锁变量,
Kill Dead Another,在构造中CreateEvent Kill与Dead,
在InitInstance中:
while (WaitForSingleObject(m_hEventKill, 0) == WAIT_TIMEOUT)
{
进入临界区进行资源访问,也就是可以DownloadFunction();
}
在析构中CloseHandle Kill与Dead,在Delete中SetEvent Dead Another.
Top
34 楼wacky(笨笨狗)回复于 2002-10-04 20:02:18 得分 2
最好将你的子线程定义为链表,可以随时增加与减少下载块。Top
35 楼everandforever(Forever)回复于 2002-10-04 21:34:24 得分 2
有2个问题:
1。线程退出时提示(没有运行完): Detected memory leaks!
_______
上面已经有人解释,如果要求不高,完全可以忽略。
2。仍然不能拖动!
——————————————————
while (thread_finished_flag == FALSE){
}
去掉了么?不然就是你在别的地方,还有死循环。
——————————————
如果你只是要程序能运行,这样就可以了。如果要它好好运行,就要照楼上的
话改。
Top
36 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-07 15:29:48 得分 0
TO: caitou123(自向红尘取烦恼)
我按照 大虾 说的方法 遇到 2 个问题:
1。
static i=0; //你的线程数
// HANDLE thread[4]; 我该在什么地方定义?其中的4是不是最大线程数?还是具有其他含义?
thread[i++]=ct->m_hThread
2。主线程中
HANDLE thread[stringArray.GetSize()]; //你的线程数
stringArray.GetSize() 是变量,不可能定义HANDLE thread[变量]
我可以直接定义一个较大的数,有影响吗?
Top
37 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-07 15:31:46 得分 0
TO:
wacky(笨笨狗)
能够将你讲的方法详细点吗?
先谢了!Top
38 楼caitou123(自向红尘取烦恼)回复于 2002-10-07 17:11:25 得分 2
HANDLE thread[4] 就是主线程中的 HANDLE thread[stringArray.GetSize()];
定义成全局变量吧。
我不知你有多少线程,4是随意写的,可以直接定义一个较大的数(我在书上看到的,说一个进程拥有的资源数,包括各种内核,图标等,最大可到1万个)。
我建议你看看侯捷译的《Win32多线程编程〉,或,《Windows 核心编程>
Top
39 楼wacky(笨笨狗)回复于 2002-10-07 18:13:54 得分 2
因为你定义的是多线程是基于WinThread的,所以定义信号变量HANDLE是为了使线程同步,并且不出现资源强占与死锁。
一句话也说不清的,建议先看看多线程编程的书,我有一本电子的,若要,请来信索取:e_bean@sohu.comTop
40 楼songfeng163(东方游侠)回复于 2002-10-07 21:15:19 得分 2
up!gz!Top
41 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-07 22:02:35 得分 0
TO:
caitou123(自向红尘取烦恼)
我按照 大虾的方法做了,但感觉还是没对
我把线程的代码改成
for(int i=0; i<1000; i++){
TRACE("%d ",i);
}
但输出的结果是:
0,1,2,3,4,..658
0,1,2,3,4,..194
0,1,2,3,4,..194
没有什么其他异常的输出
Top
42 楼wacky(笨笨狗)回复于 2002-10-07 22:11:33 得分 2
MultiThreads synchronization?Top
43 楼icebamboo(求助高手!)回复于 2002-10-07 22:40:46 得分 2
很高深呀!看来还得磨磨刀,才行呀!Top
44 楼fengxuchao()回复于 2002-10-08 21:58:50 得分 2
DownLoadFunction应该为DownloadThead类的成员函数Top
45 楼caitou123(自向红尘取烦恼)回复于 2002-10-09 20:25:00 得分 2
"没有什么其他异常的输出" 是什么意思?
如果是在线程里加的,for(int i=0; i<1000; i++){
TRACE("%d ",i);
}
也是对的,因为线程创建后,就由cpu来调度了。
我说的方法,就是保证在子线程未结束时,禁止主线程的终止。
Top
46 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-10 00:14:05 得分 0
我说的方法,就是保证在子线程未结束时,禁止主线程的终止。
可以具体点吗?
谢了!Top
47 楼ttzzgg_80713(身无立锥地,常有四海心---老子有条命)回复于 2002-10-10 00:33:14 得分 2
我刚好也做 一个,是断点续传的。多线程。(8个)嘻嘻,可以主界面可以响应任务事件呀。Top
48 楼xuboT(向張自忠將軍致敬)回复于 2002-10-12 00:48:57 得分 2
當你創建sub thread的時候,將ThreadID保存入一個數組,然後在主纖程末,用WaitForMultipleObjects()函數,具體可以參攷<Windows核心編程>,樓上几位說得很清楚了啊,順便參攷MSDN就行了。Top
49 楼3236(Arcol)回复于 2002-10-12 03:01:47 得分 2
问题出在while (thread_finished_flag == FALSE){ }中
把它去掉,或插入sleep代替
线程之间同步不应用thread_finished_flag,这样会阻塞的,你可以试用event或msg代替
老兄,你哪儿建了第二个线程了?Top
50 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-12 10:32:33 得分 0
for(int i=0; i<stringArray.GetSize(); i++ ){
fileInfo = (CStringArray *)stringArray.GetAt(i);
new DownloadThead(down,fileInfo->GetAt(0),path+fileInfo->GetAt(1));
}
这里就是 创建线程啊!Top
51 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-12 10:33:00 得分 0
TO:
3236(Arcol) 可以具体点好吗?Top
52 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-12 10:35:03 得分 0
分不够可以 另外开帖 再加
焦急等待中。。。。Top
53 楼3236(Arcol)回复于 2002-10-12 22:37:46 得分 2
对不起,明天要考试,过两天我会回来的
你还是开个新帖吧,把你的问题说清楚,说详细一点
到现在我还不是很清楚,你需要的是什么
象下面你写的程序
for(int i=0; i<stringArray.GetSize(); i++ ){
fileInfo = (CStringArray *)stringArray.GetAt(i);
new DownloadThead(down,fileInfo->GetAt(0),path+fileInfo->GetAt(1));
}
当中,DownloadThead构造时,你在最后用了一句
while (thread_finished_flag == FALSE){}的无限循环,到底为什么?要是这样的话,for循环只跑了一次,就被阻塞了,你不是说了要建立好几个线程吗?但现在这样只能等到第2个线程跑完才能建立第3个线程,第3个线程跑完才能建立第4个线程,...,这样子你就永远都不能同时建立好几个线程。再说,阻塞是占用CPU资源的,所以你的程序就象死掉的样子。
还有你的程序是基于SDK还是MFC的?最好也说清楚
至于各位所回答的都是关于线程同步的问题,主要用的是event(使用CreateEvent和WaitForSingleObject等方法辅助)、msg(使用PostThreadMessage 和GetMessage等方法辅助),当然除了这两种方法以外还有mutex、Semaphore,dde、共享内存、系统环境量、本地tcp通讯,管道、邮槽、甚至文件、数据库等都可以进行线程或进程同步、通信。你所用的while (thread_finished_flag == FALSE){}其实也是一种方法,只是用得不对而儿
我看你对线程的概念是有一定的误会,先看看书(按我所说的方法查一下msdn),然后把你的问题和程序整理一下,再开一帖吧Top
54 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-17 17:12:39 得分 0
我都看过了
但我有一点没有明白:为什么每个线程只执行了一部分就终止了Top
55 楼HelloWorld()回复于 2002-10-17 19:12:13 得分 2
看候捷的《win32多线程。。。》。那里有一些例子。Top
56 楼3236(Arcol)回复于 2002-10-17 19:20:20 得分 2
线程结束有3个条件
1.你使用代码强制令它终止。
2.线程函数运行结束(不论是否正常结束)。
3.主线程(进程)结束。(可以说成是创建线程的父线程)
我估计你的问题是第2或第3点。
现在我只讨论第2点,也就是说你的DownLoadFunction中遇到return指令。
理论上DownLoadFunction这个线程过程应是一个死循环,就象阻塞了一样,直到你需要它退出时才发一个exit message(由主线程发出)。
例如:while(1){...};//但如果只是这样就会占用100%的CPU资源,因为程序一直在跑,没机会交回操作系统,这个死循环也太死了。
因此就有了一个while(::GetMessage(&msg,NULL,0,0)){...};
当中GetMessage就是交回操作系统处理,如果没有message,线程就被挂起,GetMessage不返回值给你,就象是你在等待操作系统回答,但操作系统死活都不理你,它干别的事去了。
同样用WaitForSingleObjectcs或WaitForMultipObjectcs也能达到同样的效果。
Top
57 楼3236(Arcol)回复于 2002-10-17 19:32:00 得分 2
补充:
关于第3点
当然,主线程也必须是一个"死"循环,要不程序也会有象第3点的问题。
如果你的程序是基于SDK写的,你就要自己去写这个循环。
如果你的程序是基于MFC写的,哪就不用担心,MFC已经帮你做了,其实如果把MFC框架展开,也会找到类似while(::GetMessage(&msg,NULL,0,0)){...}的语句。
以上我所提到的"程序"只是指一般的程序,不包括组件,dll等特殊的程式Top
58 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-17 19:48:06 得分 0
请 3236(Arcol) 大侠再看看:
UINT DownLoadFunction(LPVOID lParam)
{
DownloadThead * pDownI = (DownloadThead *)lParam;
if (pDownI == NULL){
pDownI->thread_finished_flag = TRUE;
return -1;
}
pDownI->down.Download( pDownI->downloadUrl , pDownI->savePath);
pDownI->thread_finished_flag = TRUE;
return 0;
}
最开始代码是这样的,程序可以执行,唯一 一个缺点是,主线程好象阻塞了,对话筐不能拖动。(我的本意是,让子线程执行下载,主线程控制下载线程的开始,暂停,停止),现在连主线程的对话筐都锁死了。Top
59 楼3236(Arcol)回复于 2002-10-18 12:18:48 得分 2
在回答前先得问你,程序是基于MFC写的吗?
如果是的话
你主线程依然是使用
while (thread_finished_flag == FALSE){};吗?
这和我所说的while(1){...};有什么区别?
都是死循环,虽然有逃生机会,但也太死了吧。
要注意,操作系统根本就没机会处理其它东西,你的对话框就别想动了。
我看,你的思想是对的,但做法却错了,要记住,windows程序不再是过程程序,它是由事件驱动的。
就说你的程序,线程控制下载线程的开始,暂停,停止是对的,但在同一个过程(函数)里面不应该同时处理子线程的“开始,暂停,停止”三个问题。你试着往对话框放3个按扭,分别表示“开始,暂停,停止”三个问题,然后在3个OnClick事件里分别处理这3个问题,你就会更清楚什么叫事件驱动了。在主线程中,一个事件(例如OnClick)响应后,应立即或尽快返回给系统(就是退出那个响应函数),而你呢?却一直在while()里头转!哪不是你在等操作系统,而是系统在等你啊!系统还有机会处理其它事件吗?
另外,关于线程问题中,还有一个优先级问题,一般来说主线程要高于分线程,但所有线程都不应高于标准级,如非工程或驱动核心代码不能使用高优先级,默认就如此(莫非你改过?)。你可以烟酒烟酒。Top
60 楼newkey007(无限天空 www.xDrv.com)回复于 2002-10-18 12:22:56 得分 0
已经开第2帖学基础知识了:
请各位大侠指点
http://expert.csdn.net/Expert/topic/1106/1106349.xml?temp=3.846377E-02Top
61 楼3236(Arcol)回复于 2002-10-18 12:31:05 得分 20
还有一点,我想知道
pDownI->down.Download里头究竟在干嘛?
是不是很复杂的?如果太复杂,这里会占用很多CPU资源的,尤其是在网络访问要等待时,而在等待时又不让系统干别的事,结果会导致子线程占用CPU过多,而令主线程没时间处理。所以有2点可以改进改进
1.子线程也完全使用事件驱动的方式,就是借助WaitForMultipObjectcs等方法。
2.适当降底子线程优先级。Top




