1,線程概述 線程是程序匯中獨立的指令流。線程有一個優先級,實際上正在處理的程序的位置計數器,一個存儲其局部變量的棧。每個線程都有自己的棧。但應用程序的內存和堆由一個進程的所有線程共享。 進程包含資源,如windows句柄,文件句柄或其他內核對象。每個進程都分配了虛擬內存。一個進程至少包含一個線程。操作系統會調度線程。
總結: 同步代碼區域(代碼塊):lock, ?Monitor, SpinLock, Mutex,WaitHandle,Semaphore,EventWaitHandle,AutoRestEvent/ManualResetEvent. Barrier, ReadWriterLock(Slim) 多線程變量同步:InterLocked,?
進程間同步: Mutex, Semaphore,
2,異步委托: 創建線程的一種簡單方式是定義一個委托,并異步調用它。委托時方法類型安全的引用。Delegate類還支持異步調用委托,在后頭創建一個執行任務的線程。 委托使用線程池來完成異步調用。 public delegate int TakesAWhileDelegate(int data, int ms); 2.1投票: IAsyncResult ar=al.BeginInvoke(1,3000, null, null); ? ? ? int result=dl.EndInvoke(ar); 2.2 等待句柄 ?(WaitHandle)
1 class Program
2 {
3 public delegate int TakesAWhileDelegate(
int data,
int ms);
4 static int TakesAWhile(
int data,
int ms)
5 {
6 Console.WriteLine(
" TakesAWhile started " );
7 Thread.Sleep(ms);
8 Console.WriteLine(
" TakesAWhile completed " );
9 return ++
data;
10 }
11 private static void Main(
string [] args)
12 {
13 Console.WriteLine(
" Main Begin. " );
14 TakesAWhileDelegate dl =
TakesAWhile;
15 IAsyncResult ar = dl.BeginInvoke(
2 ,
3000 ,
null ,
null );
16
17 // ar.IsCompleted
18 // ar.AsyncWaitHandle.WaitOne(50)
19
20 dl.EndInvoke(ar);
21 Console.WriteLine(
" Main() end. " );
22 Console.ReadLine();
23 }
24 }
投票(ar.IsCompleted) 或者等待句柄(ar.AsyncWaitHandle.WaitOne(50, false) 2.3 異步回調 (dl.BeginInvoke(1,3000, TakesAWhileCompleted, dl) ) 傳入一個回調函數委托,來異步執行。
1 class Program
2 {
3 public delegate int TakesAWhileDelegate(
int data,
int ms);
4 static int TakesAWhile(
int data,
int ms)
5 {
6 Console.WriteLine(
" TakesAWhile started " );
7 Thread.Sleep(ms);
8 Console.WriteLine(
" TakesAWhile completed " );
9 return ++
data;
10 }
11 private static void Main(
string [] args)
12 {
13 Console.WriteLine(
" Main Begin. " );
14 TakesAWhileDelegate dl =
TakesAWhile;
15 dl.BeginInvoke(
2 ,
3000 , ar =>
16 {
17 if (ar ==
null )
18 throw new ArgumentNullException(
" ar " );
19 TakesAWhileDelegate dl1 = ar.AsyncState
as TakesAWhileDelegate;
20 Trace.Assert(dl1 !=
null ,
" Invalid object type " );
21 int result =
dl1.EndInvoke(ar);
22 Console.WriteLine(
" result: {0} " , result);
23 },
null );
24
25 Console.WriteLine(
" Main() end. " );
26 Console.ReadLine();
27 }
28 }
回調方法 3,Thread類 3.1 給線程傳遞數據 1,使用帶ParameterizedThreadStart委托參數的Thread構造函數。2,創建自定義類,把線程的方法定位實例方法,這樣就可以初始化實例的數據,之后啟動線程。 3.2 后臺線程: 只要有一個前臺線程在運行,應用程序的進程就在運行。如果多個前臺線程在運行,而Main()方法結束了,應用程序的進程依然是激活的,直到所有前臺線程完成其任務為止。
private static void Main(
string [] args){ var t1 =
new Thread(ThreadMain) {Name =
" MyNewThread " , IsBackground =
false };t1.Start();Console.WriteLine( " Main Thread ending now. " );} static void ThreadMain(){Console.WriteLine( " Thread {0} started " , Thread.CurrentThread.Name);Thread.Sleep( 3000 );Console.WriteLine( " Thread {0} Completed " ,Thread.CurrentThread.Name);} 前臺線程示例 3.3 線程的優先級?
4 線程池 5,任務 5.1 啟動任務:
啟動任務代碼 TaskFactory tf =
new TaskFactory();Task t1 =
tf.StartNew(TaskMethod);Task t2 =
Task.Factory.StartNew(TaskMethod);Task t3 =
new Task(TaskMethod);t3.Start(); ?5.2 連續的任務 Task t1=new Task(DoOnFirst); Task t2=t1.ContinueWith(DoOnSecond); 5.3任務層次結構 6 Parallel 類 Parallel.For Parallel.ForEach() Parallel.Invoke(fun1,fun2);
1 private static void Main(
string [] args)
2 {
3 Parallel.Invoke(TaskMethod1,TaskMethod2);
4
5 Console.ReadLine();
6 }
7
8 static void TaskMethod1()
9 {
10 Console.WriteLine(
" 1running in a task. " );
11 Console.WriteLine(
" Task id: {0} " , Task.CurrentId);
12 }
13 static void TaskMethod2()
14 {
15 Console.WriteLine(
" 2running in a task. " );
16 Console.WriteLine(
" Task id: {0} " , Task.CurrentId);
17 }
Parallel.Invoke Code 7. 取消架構
8, 線程問題: ?爭用條件和死鎖 8.1 爭用條件:
1 public class StateObject
2 {
3 private int state =
5 ;
4
5 public void ChangeState(
int loop)
6 {
7 lock (
this )
8 {
9 if (state ==
5 )
10 {
11 state++
;
12 Trace.Assert(state ==
6 ,
" Race condition ocurred after " + loop +
" loops " +
Task.CurrentId);
13 if (loop %
1000000 ==
0 )
14 {
15 Console.WriteLine(
" after " + loop +
" loops " +
Task.CurrentId);
16 }
17 }
18 state =
5 ;
19 }
20
21 }
22 }
23
24 public class SampleTask
25 {
26 public void RaceCondition(
object o)
27 {
28 Trace.Assert(o
is StateObject,
" o must be of type StateObject. " );
29 StateObject state = o
as StateObject;
30 int i =
0 ;
31 while (
true )
32 {
33 state.ChangeState(i++
);
34 }
35 }
36 }
37
38 public class SampleThread
39 {
40 public SampleThread(StateObject s1, StateObject s2)
41 {
42 this .s1 =
s1;
43 this .s2 =
s2;
44 }
45
46 private StateObject s1;
47 private StateObject s2;
48
49 public void Deadlock1()
50 {
51 int i =
0 ;
52 while (
true )
53 {
54 lock (s1)
55 {
56 lock (s2)
57 {
58 s1.ChangeState(i);
59 s2.ChangeState(i++
);
60 Console.WriteLine(
" still running, {0} " , i);
61
62 }
63 }
64 // Thread.Yield();
65 }
66 }
67 public void Deadlock2()
68 {
69 int i =
0 ;
70 while (
true )
71 {
72 lock (s2)
73 {
74 lock (s1)
75 {
76 s1.ChangeState(i);
77 s2.ChangeState(i++
);
78 Console.WriteLine(
" still running, {0} " , i);
79
80 }
81 }
82 // Thread.Yield();
83 }
84 }
85 }
86
87 private static void Main(
string [] args)
88 {
89 var state1 =
new StateObject();
90 var state2 =
new StateObject();
91
92 SampleThread st =
new SampleThread(state1, state2);
93
94 Task.Factory.StartNew(st.Deadlock1);
95 Task.Factory.StartNew(st.Deadlock2);
96
97 Console.ReadLine();
98 }
死鎖演示代碼 9, 同步 9.1 Lock 語句 棧是線程獨立的,但不是私有的。所有線程的棧內所有內容,都可以被其他線程訪問。為什么不用 lock(this) ? 因為這通常超出我們的控制,因為其他人也有可能lock這個對象。一個私有的對象是更好的選擇。避免lock一個公開類型,或者超出你代碼的控制的實例。 Tips:可以提供線程安全的原子操作。
1 class Program
2 {
3 public class SharedState
4 {
5 public int State {
get ;
set ; }
6 }
7
8 public class Job
9 {
10 private SharedState sharedState;
11
12 public Job(SharedState sharedState)
13 {
14 this .sharedState =
sharedState;
15 }
16
17 public void DoTheJob()
18 {
19 for (
int i =
0 ; i <
50000 ; i++
)
20 {
21 sharedState.State +=
1 ;
22 }
23 }
24 }
25
26 private static void Main(
string [] args)
27 {
28 int numTasks =
20
29 ;
30 var state =
new SharedState();
31 var tasks =
new Task[numTasks];
32 for (
int j =
0 ; j <
5 ; j++
)
33 {
34 state.State =
0 ;
35 for (
int i =
0 ; i < numTasks; i++
)
36 {
37 tasks[i] =
new Task(
new Job(state).DoTheJob);
38 tasks[i].Start();
39
40 }
41
42 for (
int i =
0 ; i < numTasks; i++
)
43 {
44 tasks[i].Wait();
45
46 }
47 Console.WriteLine(
" summarized {0} " , state.State);
48 }
49
50
51 }
52
53 }
線程不安全-問題代碼 9.2 Interlocked類 Interlock類用于使變量的簡單語句原子化,線程安全方式遞增、遞減、交換和讀取。i++不是線程安全的(包含3個操作:從內存獲取、遞增1、存儲回內存,這些操作都可以被線程調度器打斷)。
9.3 Monitor類 lock語句由編譯器解釋為Monitor類: Moniter.Enter(obj) ; ? Monitor.Exit(obj); Monitor類的一個優點:可以添加一個等待被鎖定的超市值。Monitor.TryEnter(lockObj,500,ref lockToken);
1 public void DoTheJob()
2 {
3 for (
int i =
0 ; i <
50000 ; i++
)
4 {
5 bool isLocked =
false ;
6 goLabel:
7 Monitor.TryEnter(sharedState,
500 ,
ref isLocked);
8 if (isLocked)
9 {
10 sharedState.State +=
1 ;
11 Monitor.Exit(sharedState);
12 }
13 else
14 {
15 Console.WriteLine(
" lock failed. " );
16 goto goLabel;
17 }
18
19 }
20 }
Monitor.TryEnter ?9.4 SpinLock結構 適合于有大量的鎖定,而且鎖定的時間非常短。用法非常接近于Monitor類。獲得鎖使用Enter()或者TryEnter(),釋放鎖使用Exit()方法。小心SpinLock的傳送,因為是結構,所以會復制。
9.5 WaitHandle基類 Delegate BeginInvoke() 用waithandle.WaitOne(50,false)來bolck當前線程, WaitHandle是一個抽象基類,用于等待一個信號量的設置。可以等待不同的信號,因為WaitHandle是一個基類,可以派生一些類。
private static void Main(
string [] args){Action ac = () =>
{Console.WriteLine( " Action Begin. " );Thread.Sleep( 2000 );Console.WriteLine( " Action End. " );};AsyncCallback callback = (o) =>
{ var cb =
(Action)o.AsyncState;cb.EndInvoke(o);Console.WriteLine( " Callback finished. " );};IAsyncResult ar =
ac.BeginInvoke(callback, ac); while (
true ){Console.Write( " . " ); if (ar.AsyncWaitHandle.WaitOne(
50 ,
true )){Console.WriteLine( " Can get the result now. " ); break ;}}Console.ReadLine();} AsyncWaitHandle WaitOne() 等待一個,waitAll()等待多個對象,WaitAny等待多個對象的一個。WaitAll和WaitAny是靜態方法。
WaitHandle基類有一個SafeWaitHandle屬性,其中可以將本機句柄賦予一個操作系統資源,并等待該句柄。 Mutex、EventWaitHandle 和 Semaphore類繼承自WaitHandle基類。所以可以等到使用它們。 9.6 Mutex類 Mutex(mutual exclusion,互斥)是.net Framework中提供多個集成同步訪問的一個類。它非常類似于Monitor,只有一個線程能擁有鎖定。只有一個線程能獲得互斥鎖定,訪問受互斥訪問的同步代碼區域。 ? ? 在Mutex類的構造函數中,可以指定互斥是否最初由主調線程擁有。定義互斥的名稱,獲得互斥是否存在的信息。 系統能識別有名稱的Mutex
private static void Main(
string [] args){ bool isNew; using (Mutex mutex =
new Mutex(
false ,
" ProMutext " ,
out isNew)){ if (isNew){Console.WriteLine( " Get mutex lock. " );} else {Console.WriteLine( " can't get mutex lock. " );}Thread.Sleep( 3000 );}Thread.Sleep( 1000000 );Console.ReadLine();} Mutex ?
9.7 Semaphore類 信號量非常類似于互斥,其區別是多個線程使用。信號量是一種技術的互斥鎖定。使用信號量可以定義同時訪問旗語鎖定保護的資源的線程個數。 Semaphore類:可以命名,使用系統范圍內的資源,允許不同進程間同步。
static void Main(){ int threadCount =
6 ; int semaphoreCount =
4 ; var semaphore =
new Semaphore( semaphoreCount, semaphoreCount,
" ProSemaphore " ); var threads =
new Thread[threadCount]; for (
int i =
0 ; i < threadCount; i++
){threads[i] =
new Thread(ThreadMain);threads[i].Start(semaphore);} for (
int i =
0 ; i < threadCount; i++
){threads[i].Join();}Console.WriteLine( " All threads finished " );} static void ThreadMain(
object o){Semaphore semaphore = o
as Semaphore;Trace.Assert(semaphore !=
null ,
" o must be a Semaphore type " ); bool isCompleted =
false ; while (!
isCompleted){ if (semaphore.WaitOne(
600 )){ try {Console.WriteLine( " Thread {0} locks the semaphore " ,Thread.CurrentThread.ManagedThreadId);Thread.Sleep( 4000 );} finally {semaphore.Release();Console.WriteLine( " Thread {0} releases the semaphore " ,Thread.CurrentThread.ManagedThreadId);isCompleted =
true ;}} else {Console.WriteLine( " Timeout for thread {0}; wait again " ,Thread.CurrentThread.ManagedThreadId);}}} Semaphore(多線程&跨進程同步) SemaphoreSlim類是對于較短等待時間進行了優化的輕型版本,不能跨進程。不能命名,不使用內核信號量,不能跨進程。
private static void Main(
string [] args){ int threadCount =
6 ; int semaphoreCount =
4 ; var semaphore =
new SemaphoreSlim(semaphoreCount, semaphoreCount);Thread[] threads =
new Thread[threadCount]; for (
int i =
0 ; i < threadCount; i++
){threads[i] =
new Thread(ThreadMain);threads[i].Start(semaphore);} for (
int i =
0 ; i < threadCount; i++
){threads[i].Join();}Console.WriteLine( " AllThread finished! " );Console.ReadLine();} static void ThreadMain(
object o){SemaphoreSlim semaphore = o
as SemaphoreSlim;Trace.Assert(semaphore !=
null ,
" o must be a Semphore type. " ); bool isCompleted =
false ; while (!
isCompleted){ if (semaphore.Wait(
100 )){ try {Console.WriteLine( " thread {0} locks the semaphore " , Thread.CurrentThread.ManagedThreadId);Thread.Sleep( 3000 );} finally {semaphore.Release();Console.WriteLine( " Thread {0} release the semaphore " , Thread.CurrentThread.ManagedThreadId);isCompleted =
true ;}} else {Console.WriteLine( " Timeout for thread {0}; wait again " , Thread.CurrentThread.ManagedThreadId);}}} SemaphoreSlim 9.8 Event類 事件是另一個系統范圍內的資源同步方法。為了從托管代碼中使用系統事件,.net framework提供了ManualResetEvent、AutoResetEvent、ManualResetEventSlim和CountdownEvent類。
private static void Main(
string [] args){ const int taskCount =
10 ; var mEvents =
new ManualResetEventSlim[taskCount]; var waitHandles =
new WaitHandle[taskCount]; var calcs =
new Calculator[taskCount];TaskFactory taskFactory =
new TaskFactory(); for (
int i =
0 ; i < taskCount; i++
){mEvents[i] =
new ManualResetEventSlim(
false );waitHandles[i] =
mEvents[i].WaitHandle;calcs[i] =
new Calculator(mEvents[i]);taskFactory.StartNew(calcs[i].Calculation, Tuple.Create(i +
1 , i +
3 ));} for (
int i =
0 ; i < taskCount; i++
){ int index =
WaitHandle.WaitAny(waitHandles); if (index ==
WaitHandle.WaitTimeout){Console.WriteLine( " Timeout!! " );} else {mEvents[index].Reset();Console.WriteLine( " finished task for {0}, result: {1} " , index, calcs[index].Result);Thread.Sleep( 100 );}}Console.ReadLine();} public class Calculator{ private ManualResetEventSlim mEvent; public int Result {
get ;
private set ; } public Calculator(ManualResetEventSlim ev){ this .mEvent =
ev;} public void Calculation(Object obj){Tuple <
int ,
int > data = (Tuple<
int ,
int >
)obj;Console.WriteLine( " Task {0} starts calculation " , Task.CurrentId);Thread.Sleep(( 3000 ));Result = data.Item1 +
data.Item2;Console.WriteLine( " Task {0} is ready " , Task.CurrentId);mEvent.Set();}} ManualResetEvent 把任務分支到多個任務中,并在以后合并結果,使用新的CountdownEvent類很有用。 不需要位每個任務創建一個單獨的事件對象,而只需要創建一個事件對象。
var mEvents = new ManualResetEventSlim[taskCount]; // var cEvent = new CountdownEvent(taskCount);
var waitHandles = new WaitHandle[taskCount]; var calcs = new Calculator[taskCount];
int index = WaitHandle.WaitAny(waitHandles);//wait
//tasks mEvent.Set();//all thread set; //continue
private static void Main(
string [] args){ const int taskCount =
10 ; var cEvent =
new CountdownEvent(taskCount); var calcs =
new Calculator[taskCount];TaskFactory taskFactory =
new TaskFactory(); for (
int i =
0 ; i < taskCount; i++
){calcs[i] =
new Calculator(cEvent);taskFactory.StartNew(calcs[i].Calculation, Tuple.Create(i +
1 , i +
3 ));}cEvent.Wait();Console.WriteLine( " All finished. " );Console.ReadLine();} public class Calculator{ private CountdownEvent cEvent; public int Result {
get ;
private set ; } public Calculator(CountdownEvent ev){ this .cEvent =
ev;} public void Calculation(Object obj){Tuple <
int ,
int > data = (Tuple<
int ,
int >
)obj;Console.WriteLine( " Task {0} starts calculation " , Task.CurrentId);Thread.Sleep(( 3000 ));Result = data.Item1 +
data.Item2;Console.WriteLine( " Task {0} is ready " , Task.CurrentId);cEvent.Signal();}} CountdownEvent ?9.9 Barrier 類 適合于工作有多個任務分支且以后又需要合并工作的情況。
?var barrier = new Barrier(numberTasks + 1); ?barrier.SignalAndWait();//wait //tasks barrier.RemoveParticipant();//2 left
barrier.RemoveParticipant();//1 left
//continue. 9.10 ReadWriterLockSlim類 允許多個讀取器。同時只有一個寫入器工作,此時讀取器不能工作。
private static List<
int > items =
new List<
int >() {
0 ,
1 ,
2 ,
3 ,
4 ,
5 }; static ReaderWriterLockSlim rwl =
new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); static void ReadMethod(
object reader){ try {rwl.EnterReadLock(); for (
int i =
0 ; i < items.Count; i++
){Console.WriteLine( " read {0}, loop: {1}, item:{2} " , reader, i, items[i]);Thread.Sleep( 40 );}} finally {rwl.ExitReadLock();}} static void WriterMethod(
object writer){ try { while (!rwl.TryEnterWriteLock(
50 )){Console.WriteLine( " Writer {0} waiting ,current reader count: {1} " , writer, rwl.CurrentReadCount);}Console.WriteLine( " Writer{0} acquired the lock. " , writer); for (
int i =
0 ; i < items.Count; i++
){items[i] ++
;Thread.Sleep( 50 );}Console.WriteLine( " Writer {0} finished. " , writer);} finally {rwl.ExitWriteLock();}} private static void Main(
string [] args){ var taskFactory =
new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None); var tasks =
new Task[
6 ];tasks[ 0 ] = taskFactory.StartNew(WriterMethod,
1 );tasks[ 1 ] = taskFactory.StartNew(ReadMethod,
1 );tasks[ 2 ] = taskFactory.StartNew(ReadMethod,
2 );tasks[ 3 ] = taskFactory.StartNew(WriterMethod,
2 );tasks[ 4 ] = taskFactory.StartNew(ReadMethod,
3 );tasks[ 5 ] = taskFactory.StartNew(ReadMethod,
4 ); foreach (Task task
in tasks){task.Wait();}Console.WriteLine( " All finished. " );Console.ReadLine();} ReadWriterLockSlim ?
?
10 Timer類
?
?
轉載于:https://www.cnblogs.com/netact/p/3659737.html
總結
以上是生活随笔 為你收集整理的C# 线程、任务和同步 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。