一、进程是一个包含了某些资源的内存区域,进程中包含的一个或多个执行单元称线程。
二、创建和销毁进程
using System.Diagnostics;
using System.Threading;
class Program {
staticvoid
// 创建进程
Processprocess = Process.Start("notepad.exe", "hello.txt");
//Sleep one second.
Thread.Sleep(10000);
// 销毁进程
process.Kill();
}
}
三、避免在同一台机器上同时运行同一个运用程序的多个实例
using System.Diagnostics;
class Program {
static void
if ( TestIfAlreadyRunning() ) {
System.Console.WriteLine("Thisapp is already running!");
System.Console.ReadKey();
}
else{
System.Console.ReadKey();
}
}
static boolTestIfAlreadyRunning() {
Process processCurrent = Process.GetCurrentProcess();
Process[] processes = Process.GetProcesses();
foreach ( Processprocess in processes )
if ( processCurrent.Id != process.Id )
if ( processCurrent.ProcessName ==process.ProcessName )
return true;
return false;
}
}
四、一个线程包括以下内容:1
- 一个指向当前执行指令的指令指针
- 一个栈
- 一个寄存器值的集合。定义了一部分正在执行线程的处理器状态的值;
- 一个私有的数据区域;
五、关于线程
1、 线程开始thread.start();
2、 threadA.join();阻止线程threadA被调用,直到threadA线程终止,或经过了指定的时间。
3、 当线程A调用了线程B的Abort()方法,建议调用B的join()方法,让A一直等待到B终止。
4、 ThreadA.sleep(); threadA.wait(); threadA.join(); ---à线程阻塞
5、 ThreadA.suspend()线程挂起---ThreadA.resume()
六、关于Monitor类
1、 Moniter的Enter及Exit:保护被同步的对象
using System.Threading;
class Program {
staticlong counter = 1;
staticvoid
Threadt1 = new Thread(f1 );
Threadt2 = new Thread(f2 );
t1.Start(); t2.Start(); t1.Join();t2.Join();
}
staticvoid f1() {
for(int i = 0; i < 5; i++){
try{
Monitor.Enter(typeof( Program) );
counter *= counter;
}
finally{Monitor.Exit( typeof(Program ) ); }
System.Console.WriteLine("counter^2{0}", counter);
Thread.Sleep(10);
}
}
staticvoid f2() {
for(int i = 0; i < 5; i++){
try{
Monitor.Enter(typeof( Program) );
counter *= 2;
}
finally{Monitor.Exit( typeof(Program ) ); }
System.Console.WriteLine("counter*2{0}", counter);
Thread.Sleep(10);
}
}
七、使用Win32对象同步:互斥体、事件与信号量
1、 Waithandle抽象基类提供了3个基础类:Mutex、AutoResetEvent和Seaphore
2、 Waithandle和它的继承类有一个特点,他们都覆写了Waitone()方法并实现了Waitall、WaitAny()和SignalAndwait()静态方法。
3、 与Monitor类相比,Waithandle的继承类必须实例化后才能使用。因此这里要考虑的对象不是被同步的对象,而是用于同步的对象。
八、关于互斥体:Mutex
1、 我们可以在同一台机器甚至是远程机器的多个进程中使用同一个互斥体。
2、 Mutex类没有Monitor类的Wait()、Pulse()以及PulseAll()方法。
3、 如果需要同步的访问处在一个进程中,应该考虑使用Monitor类代替互斥体,因为他的效率更高。
4、
using System.Threading;
using System.IO;
class Program {
staticvoid
//The mutex created is named 鈥楳utexTest鈥?
MutexmutexFile = new Mutex(false, "MutexTest");
for(int i = 0; i < 10; i++){
mutexFile.WaitOne();
//Open the file, write hello i and then close it.
FileInfofi = new FileInfo("tmp.txt");
StreamWritersw = fi.AppendText();
sw.WriteLine("Hello {0}", i);
sw.Flush();
sw.Close();
System.Console.WriteLine("Hello {0}", i);
//Wait one second to make obvious the sharing of mutex.
Thread.Sleep(1000);
mutexFile.ReleaseMutex();
}
mutexFile.Close();
}
}
5、
九、基于事件的同步机制EventResetMode.AutoReset及EventResetMode.ManualReset
1、 AutoReset和ManualReset继承自WaitHandle,而WaitHandle继承自MarshalByRefObject
2、 事件没有显示定义在一个给定时间属于某个线程的某个资源的概念。事件用于在线程间传递通知,该通知表示“某个事件发生了”。被关注的事件会与实例关联。
3、 具体地说,一个线程通过调用代表时间的对象的waitone()这个阻塞方法来等待一个事件被触发。另一个线程通过调用事件对象的set()方法以触发事件从而使得第一个线程继续执行。
4、 自动重置事件与手工重置事件的区别在于,后只需要调用reset()方法将事件返回到非活动状态。
以下是一个具体的实例:
using System;
using System.Threading;
class Program {
staticEventWaitHandle[] events;
staticvoid
events = new EventWaitHandle[2];
// Initialevent state聽: false
events[0] = new EventWaitHandle(false ,EventResetMode.AutoReset);
events[1] = new EventWaitHandle(false ,EventResetMode.AutoReset);
Threadt0 = new Thread(ThreadProc0 );
Threadt1 = new Thread(ThreadProc1 );
t0.Start(); t1.Start();
//此处调用wait阻塞方法等待一个事件被触发
AutoResetEvent.WaitAll(events );
Console.WriteLine("MainThread: Thread0 reached 2" +
" and Thread1 reached 3." );
t0.Join();t1.Join();
}
staticvoid ThreadProc0() {
for( int i = 0; i < 5; i++ ) {
Console.WriteLine("Thread0: {0}", i );
//此处通过set方法触发该事件
if( i == 2 ) events[0].Set();
Thread.Sleep(100 );
}
}
staticvoid ThreadProc1() {
for( int i = 0; i < 5; i++ ) {
Console.WriteLine("Thread1: {0}", i );
//此处通过set方法触发该事件
if( i == 3 ) events[1].Set();
Thread.Sleep(60 );
}
}
}
十、信号量semaphore
1、 Semaphore类继承自Waithandle抽象类;
2、 一个System.Threading.Semaphore类的实例可以用来限制对一个资源的并发访问数。
3、 下例中,当调用wait()方法试图进入一个信号量的时候,如果当时已经进入的线程的数量达到某个最大值,该线程就会阻塞。这个最大的入口的数量由semaphore类的构造函数的第二个参数设定,而第一个参数则定义了初始时的入口数量。
using System;
using System.Threading;
class Program {
staticSemaphore semaphore;
staticvoid
//Initial number of free slots 空位的数量 : 2.
//Maximal number of slots used simulteanously : 5.
//Number of slot owned by the main thread 主线程占据的空位 : 3 (5-2).
semaphore = new Semaphore( 2,5 );
for( int i = 0; i < 3; ++i ) {
Threadt = new Thread(WorkerProc );
t.Name = "Thread" + i;
t.Start();
Thread.Sleep(30 );
}
}
staticvoid WorkerProc() {
for( int j = 0; j < 3; j++ ) {
semaphore.WaitOne();
Console.WriteLine(Thread.CurrentThread.Name + ": Begin" );
Thread.Sleep(200 ); //Simulate a 200 milliseconds task.
Console.WriteLine(Thread.CurrentThread.Name + ": End" );
semaphore.Release();
}
}
}
十一、 利用System.Runtime.Remoting.Contexts.SynchronizationAttribute实现同步
1、 将System.Runtime.Remoting.Contexts.SynchronizationAttribute用用于某个类后,该类的实例无法被多个线程同时访问,我们说,这样的类是线程安全的
using System.Runtime.Remoting.Contexts;
using System.Threading;
[Synchronization(SynchronizationAttribute.REQUIRED)]
public class Foo :System.ContextBoundObject {
publicvoid DisplayThreadId() {
System.Console.WriteLine( "Begin:ManagedThreadId = " +
Thread.CurrentThread.ManagedThreadId );
Thread.Sleep(1000 );
System.Console.WriteLine( "End: ManagedThreadId = " +
Thread.CurrentThread.ManagedThreadId );
}
}
public class Program {
staticFoo m_Objet = newFoo();
staticvoid
Threadt0 = new Thread(ThreadProc );
Threadt1 = new Thread(ThreadProc );
t0.Start(); t1.Start();
t0.Join(); t1.Join();
}
staticvoid ThreadProc() {
for( int i = 0; i < 2; i++ )
m_Objet.DisplayThreadId();
}
}
十二、 CLR的线程池,System.Thread.ThreadPool类
1、 线程池负责:
u 创建于销毁线程
u 分配任务
u 优化对线程的使用
2、 使用THreadPool.QueueUserWorkItem()静态方法提交自己的任务以及他们的处理方法。
3、 创建一个定时器,利用它周期性的向池中提交预先定义好的任务以及他们的处理方法。这种情况下,必须使用ThreadPool.RegsiterWaitForSingleObject()方法。
using System.Threading;
public class Program {
publicstatic void
ThreadPool.RegisterWaitForSingleObject(
newAutoResetEvent( false),
//Method which represents the periodic task.
newWaitOrTimerCallback( ThreadTaskWait ),
null, // No parameterfor the periodic task.
2000, // Period = 2seconds.
false);// Trigger the periodic task for ever.
//Post 3 user tasks with parameters 0,1,2.
for( int count = 0; count < 3; ++count )
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadTask),count);
//Wait 12 seconds before shutting down the process.
//Keep in mind that threadpool threads are background.
Thread.Sleep(12000 );
}
staticvoid ThreadTask( objectobj ) {
System.Console.WriteLine( "Thread#{0} Task#{1} Begin",
Thread.CurrentThread.ManagedThreadId ,obj.ToString());
Thread.Sleep(5000 );
System.Console.WriteLine( "Thread#{0} Task#{1} End",
Thread.CurrentThread.ManagedThreadId , obj.ToString());
}
staticvoid ThreadTaskWait( objectobj, bool signaled ) {
System.Console.WriteLine("Thread#{0} TaskWait",
Thread.CurrentThread.ManagedThreadId );
}
}
十三、 定时器 System.Timer.Timer类
1、 Interval[Get;Set;]属性,可以通过它设置精度为毫秒的执行时间;
2、 一个ElapsedEventHandler类型的委托对象引用表示被执行的任务的方法。该引用被表示为ElapsedEventHandler类型的Elapsed事件。
using System.Timers;
class Program {
staticTimer Timer1 = newTimer();
staticTimer Timer2 = newTimer();
staticvoid
Timer1.Interval = 1000; // Period = 1second.执行时间为1秒
Timer1.Elapsed += new ElapsedEventHandler(PeriodicTaskHandler );
Timer2.Interval = 2000; // Period = 2seconds.执行时间为两秒
//Timer2的事件加载了两次。执行两遍
Timer2.Elapsed += new ElapsedEventHandler(PeriodicTaskHandler );
Timer2.Elapsed += new ElapsedEventHandler(PeriodicTaskHandler );
Timer1.Start();Timer2.Start();
System.Threading.Thread.Sleep( 5000 ); //Sleep 5 seconds.
Timer1.Stop(); Timer2.Stop();
}
staticvoid PeriodicTaskHandler( object sender, ElapsedEventArgse ) {
stringstr = ( sender == Timer1 ) ? "Timer1 ": "Timer2 ";
str +=e.SignalTime.ToLongTimeString();
System.Console.WriteLine( str );
}
}
十四、 异步方法调用与回调
1、 异步调用:begininvoke与endinvoke
2、 回调方法:可以为异步调用指定一个方法,该方法在异步调用结束的时候自动被调用,这样的方法被称为回调方法。调用回调方法的线程与调用异步方法的线程是同一个线程
3、 为了使用回调方法,只需要一个System.AsyncCallCallback类型的委托对象引用该方法,将该对象作为倒数第二个参数传入到begininvoke()方法中。回调方法必须符合委托的类型定义,也就是说它必须以一个IAsyncResult接口代表了一个继承自WaitHandle类的同步对象,但是该对象在异步处理完成后立即被触发,而此时回调方法还未被调用,因此,该对象没有等到回调方法执行完毕。
下面这个例子很好地示范了autoresetevent和回调方法
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;
class Program {
publicdelegate int Deleg( int a, int b );
//Initial state of the event: false.定义一个自动事件
staticAutoResetEvent ev = newAutoResetEvent( false);
staticint WriteSum( inta, int b ) {
Console.WriteLine(" Thread#{0}: Sum = {1}",
Thread.CurrentThread.ManagedThreadId , a + b );
returna + b;
}
static voidSumDone(IAsyncResult async) {
//Wait a second to simulate some work.
Thread.Sleep(1000 );
Delegproc = ( (AsyncResult) async ).AsyncDelegateas Deleg;
intsum = proc.EndInvoke( async );
Console.WriteLine("Thread#{0}: Callback method sum = {1}",
Thread.CurrentThread.ManagedThreadId, sum );
ev.Set();
}
staticvoid
Delegproc = WriteSum;
//The C#2 compiler infer a delegate object of type AsyncCallback
//to reference the SumDone() method.
IAsyncResultasync = proc.BeginInvoke( 10, 10, SumDone, null);
Console.WriteLine(
"Thread#{0}:BeginInvoke() called! Wait for SumDone() completion.",
Thread.CurrentThread.ManagedThreadId);
ev.WaitOne();
Console.WriteLine(
"{0}:Bye... ", Thread.CurrentThread.ManagedThreadId);
}
}
4、 向回调方法传递状态,如果begininvooke方法的最后一个参数没有设为空值,那么可以使用它引用一个对象,触发异步调用的线程以及回调方法都可以使用该对象,在IAsyncResult接口中的AsyncState属性包含了该对象的另一个引用。它可以表示一个由回调方法设置的状态。
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;
class Program {
publicdelegate int Deleg( int a, int b );
staticint WriteSum( inta, int b ) {
Console.WriteLine("Thread#{0}: Sum = {1}",
Thread.CurrentThread.ManagedThreadId , a+b);
returna + b;
}
staticvoid SumDone( IAsyncResultasync ) {
//Wait a second to simulate some work.
Thread.Sleep(1000 );
Delegproc = ( (AsyncResult) async ).AsyncDelegateas Deleg;
intsum = proc.EndInvoke( async );
Console.WriteLine("Thread#{0}: Callback method sum = {1}",
Thread.CurrentThread.ManagedThreadId , sum );
//在IAsyncResult接口中的AsyncState属性包含了该对象的另一个引用。
( (AutoResetEvent)async.AsyncState).Set();
}
staticvoid
Delegproc = WriteSum;
//此处的ev定义在main函数内部,未定义在类级别
AutoResetEventev = new AutoResetEvent(false);
IAsyncResultasync = proc.BeginInvoke( 10, 10, SumDone, ev);
Console.WriteLine(
"Thread#{0}:BeginInvoke() called! Wait for SumDone() completion.",
Thread.CurrentThread.ManagedThreadId);
ev.WaitOne();
Console.WriteLine(
"{0}:Bye... ", Thread.CurrentThread.ManagedThreadId);
}
}
十五、 线程-资源亲缘性
1、 主要思想是,总使用同一个线程去访问某个资源。由于该资源不会被共享,也就不需要保护它免受并发访问的不良影响。
2、 System.ThreadStatic attribute默认情况下,一个静态字段将被一个进程中所有线程共享,这种特性迫使开发者去同步所有对这个字段的使用。对静态字段应用该特性,可以强迫CLR为进程中每个线程创建一个该静态字段的实例。
using System.Threading;
class Program {
[System.ThreadStatic]
staticstring str = "Initialvalue ";
staticvoid DisplayStr() {
System.Console.WriteLine("Thread#{0}Str={1}",
Thread.CurrentThread.ManagedThreadId , str);
}
staticvoid ThreadProc() {
DisplayStr();
str = "ThreadProcvalue";
DisplayStr();
}
staticvoid
DisplayStr();
Threadthread = new Thread(ThreadProc );
thread.Start();
thread.Join();
DisplayStr();
}
}