================================
一辈子,用心做一件事!
Happy stone, keep dreaming!
================================
针对上一篇的多线程学习的内容,写个说明吧!
1、主函数中这两句能否互换?为什么?
TestThread.m_testThreads[i].Start();
Thread.Sleep(100);
这里存在一个BUG,与问题4相关,后面做解释。
2、CallBack函数中这两句能否互换?为什么?会有什么不同的结果?
TestThread.m_Mutex.ReleaseMutex();
Thread.Sleep(100);
这两句换不换没什么太大的关系,因为线程互斥就是对时间及资源的互斥,因此这里是先等0.1秒再释放互斥量还是先释放互斥量再等0.1秒没有本质的关系,只是在输出上有些停顿(就当是模拟大工作量吧,呵呵)。
3、主函数能否写成这样?为什么?会有什么不同的结果?
如果这两句相换的话,主线程(Main函数所在的线程)就会在每次起动子线程后等待它所起动的线程执行完毕后再开始运行,这样就会使子线程一个一个顺序起动,而且直到前一个完成后,后一个才开始启动,所以最后的结果就是子线程一个接一个的顺序执行,而主线程则像调用子函数一样,一个一个的等待。
4、这几句的作用是什么?那么程序中还存在什么样的问题?应该做怎样的修改?
其实如果先想一下,这个例子中互斥的对象是什么,或者互斥的资源是什么,那么这个问题就很明白了。
其实这里互斥的是控制台的输出权,以及主函数与子线程函数的全局变量m_threadIndex共享问题。
因此,第四个问题其实是主函数与子线程函数关于全局变量m_threadIndex的共享问题,然而这里的程序设计上存在的BUG就是它只考虑了子函数与子函数的共享问题,而没有考虑主函数的问题,所以,问题1中,互换语句,将会做使共享资源无效,从而使变量的值出现混乱情况。改进的方法应该是在主线程与子线程中添加一个信号量。
修改后的代码参见下面的。
修改后的代码:
using System.Net;
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace Webb.Study
{
class TestThread
{
static Mutex m_Mutex = new Mutex();
static Thread[] m_testThreads = new Thread[10];
static int m_threadIndex = 0;
static AutoResetEvent[] m_events = new AutoResetEvent[]{new AutoResetEvent(false)};
static void ThreadCallBack()
{
//TestThread.m_Mutex.WaitOne();
int m_index = m_threadIndex;
m_events[0].Set();
//TestThread.m_Mutex.ReleaseMutex();
Console.WriteLine("Thread {0} start.",m_index);
for(int i=0;i<=10;i++)
{
TestThread.m_Mutex.WaitOne();
Console.WriteLine("Thread {0}: is running. {1}",m_index,i);
TestThread.m_Mutex.ReleaseMutex();
Thread.Sleep(100);
}
Console.WriteLine("Thread {0} end.",m_index);
}
public static void Main(String[] args)
{
Console.WriteLine("Main thread start.");
for(int i=0;i<TestThread.m_testThreads.Length;)
{
TestThread.m_testThreads[i] = new Thread(new ThreadStart(ThreadCallBack));
TestThread.m_testThreads[i].Start();
WaitHandle.WaitAll(TestThread.m_events);
TestThread.m_threadIndex = ++i;
m_events[0].Reset();
}
for(int i=0;i<TestThread.m_testThreads.Length;i++)
{
TestThread.m_testThreads[i].Join();
}
Console.WriteLine("Main thread exit.");
}
}
}
对第二个问题再添加一点小的说明,互换后,因为前后每个线程相差有0.1秒,而每个线程及主线程都只是小的测试,这0.1秒对于这个小例子来说就像是排了长队一样,所以最后给人的感觉像是在顺序执行。
其实不然,依次减少SLEEP的时间,最后可以减少成:
TestThread.m_testThreads[i].Start();
Thread.Sleep(0);
而它和
Thread.Sleep(0);
TestThread.m_testThreads[i].Start();
又会有什么区别呢?自己思考一下吧