一个多线程的windows控制台应用程序
一个多线程的windows控制台应用程序
一、要求:
编写一个单进程、多线程的windows控制台应用程序。
二、平台: Window XP C#
三、内容: 每个进程都有分配给它的一个或多个线程。线程是一个程序的执行部分。 操作系统把极短的一段时间轮流分配给多个线程。时间段的长度依赖于操作系统和处理器。 每个进程都开始一个默认的线程,但是能从它的线程池中创建一个新的线程。 线程是允许进行并行计算的一个抽象概念:在一个线程完成计算任务的同时,另一个线程可以对图像进行更新,两个线程可同时处理同一个进程发出的两个网络请求。
如图所示,选择操作:
1、 创建和启动一个线程。在一个进程中同时教和运行两个线程,并且可以不需要停止或者释放一个线程。
相关代码及其解释:
public class Threading1:Object { public static void startup() { }
//创建一个线程数组
Thread[] threads=new Thread[2];
for(int count=0;count
//创建线程
threads[count]=new Thread(new ThreadStart(Count)); //启动线程
threads[count].Start();
}
}
Console.Write(count+" ");
输出结果:
这里通过new方法创建了两个线程,然后使用start()方法来启动线程,两个线程的作用是:两个线程同时从1数到9,并将结果打印出来。
运行上面的程序代码时,可能会在控制台上输出多种不同的结果。从[***********]到[***********]或[***********]在内的各种情况都是可能出现的,输出结果可能与操作系统的调度方式有关。
2、 停止线程。当创建一个线程后,可以通过多种属性方法判断该线程是否处于活动状态,启动和停止一个线程等。 相关代码及其解释:
public class MyAlpha { }
public class Simple { public static int Stop() {
Console.WriteLine("Thread Start/Stop/Join"); MyAlpha TestAlpha=new MyAlpha(); //创建一个线程对象
Thread MyThread=new Thread(new ThreadStart(TestAlpha.Beta)); //开起一个线程 MyThread.Start();
while(!MyThread.IsAlive); //停止主线程
//下面创建的方法是在线程启动的时候的时候调用 public void Beta() { }
while(true) { }
Console.WriteLine("MyAlpha.Beta is running in its own thread.");
}
}
MyThread.Join(); Console.WriteLine();
Console.WriteLine("TestAlpha.Beta has finished"); //进行异常处理 try { }
catch(ThreadStateException) { } return 0;
Console.WriteLine("ThreadStateException trying to restart TestAlpha.Beta."); Console.WriteLine("Expected since aborted threads cannot be restarted."); Console.WriteLine("Try to restart the TestAlpha.Beta thread"); MyThread.Start();
输出结果:
3、 进程的同步
为了保证数据结构的稳定,必须通过使用锁来调整两个线程的操作顺序。这里通过对引用的对象申请一个锁,一旦一段程序获得该锁的控制权后,就可以保证只有它获得了这个锁并能够对该对象进行操作。同样,利用这种锁,一个线程可以一直处于等待状态,直到有能够唤醒他的信号通过变量传来为止。 相关代码及其解释:
public class Monitor1 { public static void Synchronize() {
int result=0; //Result initialized to say there is no error Cell cell=new Cell();
CellProd prod=new CellProd(cell,20); CellCons cons=new CellCons(cell,20);
Thread producer=new Thread(new ThreadStart(prod.ThreadRun)); Thread consumer=new Thread(new ThreadStart(cons.ThreadRun)); //创建了producer和consumer但是这两个线程还没有启动
try { producer.Start(); consumer.Start(); //启动两个线程 producer.Join(); consumer.Join();
//将线程producer和consumer加入,此时两个线程贻初始化完成
}
catch(ThreadStateException e) { Console.WriteLine(e); result=1;
}
catch(ThreadInterruptedException e) { Console.WriteLine(e); result=1;
}
//进行异常处理
Environment.ExitCode=result;
}
}
public class CellProd { Cell cell; int quantity=1;
public CellProd(Cell box,int request) { cell=box; quantity=request;
}
public void ThreadRun() { for(int looper=1;looper
cell.WriteToCell(looper); }
}
public class CellCons { Cell cell; int quantity=1;
public CellCons(Cell box,int request) {
cell=box; quantity=request;
}
public void ThreadRun() { int valReturned;
for(int looper=1;looper
valReturned=cell.ReadFromCell();
}
}
public class Cell { int cellContents; bool readerFlag=false; public int ReadFromCell() { lock(this) { //使用lock命令来进入线程同步块 if(!readerFlag) { //等待Cell.WriteToCell处理完毕 try { //等待Monitor.Pulse在WriteToCell进行处理 Monitor.Wait(this);
}
catch(SynchronizationLockException e) { Console.WriteLine(e);
}
catch(ThreadInterruptedException e) { Console.WriteLine(e); }
}
Console.WriteLine("Consume:{0}",cellContents); readerFlag=false; Monitor.Pulse(this);
}
//推出线程同步块 return cellContents;
}
public void WriteToCell(int n) {
} }
lock(this) { }
if(readerFlag) { }
cellContents=n;
Console.WriteLine("Produce:{0}",cellContents); readerFlag=true; //退出线程同步块 Monitor.Pulse(this);
//等待Cell.ReadFromCell处理完毕 try { }
catch(SynchronizationLockException e) { }
catch(ThreadInterruptedException e) { }
Console.WriteLine(e); Console.WriteLine(e); Monitor.Wait(this);
//等待Monitor.Pulse在WriteToCell在ReadFromCell进行处理
//使用lock命令来进入线程同步块
输出结果:
。。。 。。。
为了保证多线程同步,主要运用了以下几种方法: (1)、lock 多线程同步的关键是当一个线程正在执行某段共享代码或者正在使用某个共享资源时,其他线程不能同时进入,而需要等待前一个线程退出。实现这个功能的最直接的方法就是加锁。 C#中的lock命令来实现该功能。 (2)、Monitor.Wait(object obj) C#中如果要等待一个信号,则需要用System.Threading.Monitor类,这个方法需要在同步的程序段内执行。 (3)、Monitor.Pulse(object obj)
使用System.Threading.Monitor类中的Pulse方法来通报在等待队列的一个线程。 4、 线程池
如果许多利用了线程的应用软件都创建线程,这些线程将会因为等待某些条件(键盘或新的I/O输入等)而在等待状态中浪费了大部分的时间,C#中的System.Threading.ThreadPool对象可以解决这一问题。使用ThreadPool和事件驱动的编程机制,程序可以注册一个System.Threading.WaitHandle对象和System.Threading.WaitOrTimeCallback对象,所有的线程无需自己等待WaitHandle的释放,ThreadPool将监控所有向它注册的WaitHandle,然后再WaitHandle被释放后调用相应Threading.WaitOrTimeCallback对象的方法。 相关代码及其解释:
public class MySomeST { }
public class MyAlpha1 { Console.WriteLine("HashCount.Count=={0},Thread.CurrentThread.GetHashCode()=={1}",HashCount.Count,Thread.CurrentThre
lock(HashCount) { }
int iX=2000; Thread.Sleep(iX);
Interlocked.Increment(ref iCount); if(iCount==iMaxCount)
if(!HashCount.ContainsKey(Thread.CurrentThread.GetHashCode()))
HashCount.Add(Thread.CurrentThread.GetHashCode(),0); ((int)HashCount[Thread.CurrentThread.GetHashCode()])+1; HashCount[Thread.CurrentThread.GetHashCode()]=
ad.GetHashCode());
public void MyBeta(object state) {
Console.WriteLine("{0} {1}:",Thread.CurrentThread.GetHashCode(),((MySomeST)state).MyCook); public MyAlpha1(int MaxCount) { }
HashCount=new Hashtable(MaxCount); iMaxCount=MaxCount; public Hashtable HashCount; public ManualResetEvent eventX; public static int iCount=0; public static int iMaxCount=0; public int MyCook;
public MySomeST(int iMyCook) { }
MyCook=iMyCook;
{ Console.WriteLine();
Console.WriteLine("Setting eventX "); eventX.Set();
}
}
}
public class SimplePool { public static int Pool() { Console.WriteLine("Thread Pool:"); bool W2K=false; int MaxCount=10;
ManualResetEvent eventX=new ManualResetEvent(false);
Console.WriteLine("Queuing {0} items to Thread Pool",MaxCount); MyAlpha1 TestAlpha=new MyAlpha1(MaxCount); TestAlpha.eventX=eventX;
Console.WriteLine("Queue to Thread Pool 0"); try { ThreadPool.QueueUserWorkItem(new WaitCallback(TestAlpha.MyBeta),new MySomeST(0)); W2K=true;
}
catch(NotSupportedException) { Console.WriteLine("These API's may fail when called on a non-Window 2000 system."); W2K=false;
} if(W2K) { for(int iItem=1;iItem
ThreadPool.QueueUserWorkItem(new WaitCallback(TestAlpha.MyBeta),new MySomeST(iItem)); }
Console.WriteLine("Waiting for Thread Pool to drain"); eventX.WaitOne(Timeout.Infinite,true);
Console.WriteLine("Thread Pool has been drained(Event fired)"); Console.WriteLine();
Console.WriteLine("Load across threads"); foreach(object o in TestAlpha.HashCount.Keys)
Console.WriteLine("{0} {1}",o,TestAlpha.HashCount[o]); } return 0;
} }
输出结果:
。。。
。。。
上面的程序代码在不同的计算机上运行输出的结果可能不同。这是因为与操作系统的线程调度方式之间的差别有关。
四、总结 通过本次课程设计,对操作系统的多线程的相关知识有了更深的理解,并对C#程序设计有所掌握。 注:总的源代码在本文件夹下。