多线程遇到的问题与解决方案
多线程的两种方式:
1、线程池
ThreadPool.QueueUserWorkItem(...);
或者使用委托:
ParameterizedThreadStart start = new ParameterizedThreadStart(handleProtocol);
start.BeginInvoke(pro, null, null);
2、自定义线程
Thread myThead = new Thread(...);
myThead.Start(...);
遇到的问题:
使用线程池,在线程中创建WebBrowser对象时,会出现异常:“
ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current...
”
一种解决思路是使用自定义线程:
1 Thread myThead = new Thread(...); 2 myThead.SetApartmentState(ApartmentState.STA); 3 myThead.Start(...);
该方案虽然可以正常创建WebBrowser,但控件的消息响应无法触发,即页面加载完成的处理程序无法执行(原因估计是线程设为单一线程)。
一种解决思路是在主线程中创建WebBrowser对象,并将对象的引用传给开启的线程:
1 WebBrowser browser = new WebBrowser(); 2 browser.Navigate(...); // 这步是必须的,否则会报异常:无法获取“WebBrowser”控件的窗口句柄。不支持无窗口的 ActiveX 控件。 3 Thread myThead = new Thread(...);
4 myThead.Start(new object[]{browser});
该方案在程序刚执行时正常,之后页面加载异常(但是程序仍在正常执行,原因未知)。
一种解决思路是在主线程中创建WebBrowser对象,并使用线程池,所出现的问题如上一思路。
可行的方案待研究...
Thread.ApartmentState 默认值:MTA
Thread.IsBackground 默认值:false (即为前台线程)
线程池中的线程为后台线程(backgournd thread)
跑批程序的两种多线程管理方式:
1、使用数组保存线程对象,之后Thread.Join方法等待线程结束,如下:
Thread[] tds = new Thread[tmpThreadCount]; while (tmpThreadCount >= 1) { Thread t = new Thread(new ThreadStart(ProcessTask)); t.IsBackground = true; t.Start(); tmpThreadCount--; tds[tmpThreadCount] = t; } for (int i = 0; i < tds.Length; i++) { tds[i].Join(); }
2、在类中添加字段,使用HashTable记录每个线程的状态,在线程内部更新和检查该表的状态,如线程都运行结束则在线程内部结束进程,如下:
主线程在等待状态:Console.ReadLine();
线程内部:
//初始化线程状态 htThreadStatus.Add(threadId, true); while(true) { if(TaskQueue.Count > 0) {...} else { //队列为空时退出,并将该线程状态置为false htThreadStatus[threadId] = false; isComplete = true; ICollection hashValues = htThreadStatus.Values; foreach (bool bol in hashValues) { if (bol) { isComplete = false; break; } } if (isComplete) System.Diagnostics.Process.GetCurrentProcess().Kill(); break; } }