.net多线程学习笔记 2 thread生命周期

thread生命周期简介


在msdn上http://msdn.microsoft.com/en-us/library/system.threading.threadstate.aspx对于线程的生命周期总结如下:

StateDescription
RunningThe thread has been started, it is not blocked, and there is no pending ThreadAbortException.
StopRequestedThe thread is being requested to stop. This is for internal use only.
SuspendRequestedThe thread is being requested to suspend.
BackgroundThe thread is being executed as a background thread, as opposed to a foreground thread. This state is controlled by setting the Thread.IsBackground property.
UnstartedThe Thread.Start method has not been invoked on the thread.
StoppedThe thread has stopped.
WaitSleepJoin

The thread is blocked. This could be the result of calling Thread.Sleep or Thread.Join, of requesting a lock - for example, by calling Monitor.Enter or Monitor.Wait - or of waiting on a thread synchronization object such as ManualResetEvent.

(We will be covering all of these locking /synchronization techniques in Part 3.)

SuspendedThe thread has been suspended.
AbortRequestedThe Thread.Abort method has been invoked on the thread, but the thread has not yet received the pending System.Threading.ThreadAbortException that will


下面将详细介绍每个状态。

1.Join方法能够保证两个进程之间的先后运行关系,如下图所示:

示例如下:

using System; using System.Threading; namespace ThreadJoin { class Program { public static Thread T1; public static Thread T2; public static void Main(string[] args) { T1 = new Thread(new ThreadStart(First)); T2 = new Thread(new ThreadStart(Second)); T1.Name = "T1"; T2.Name = "T2"; T1.Start(); T2.Start(); Console.ReadLine(); } //thread T1 threadStart private static void First() { for (int i = 0; i < 5; i++) { Console.WriteLine( "T1 state [{0}], T1 showing {1}", T1.ThreadState, i.ToString()); } } //thread T2 threadStart private static void Second() { //what the state of both threads Console.WriteLine( "T2 state [{0}] just about to Join, T1 state [{1}], CurrentThreadName={2}", T2.ThreadState, T1.ThreadState, Thread.CurrentThread.Name); //join T1 T1.Join(); Console.WriteLine( "T2 state [{0}] T2 just joined T1, T1 state [{1}], CurrentThreadName={2}", T2.ThreadState, T1.ThreadState, Thread.CurrentThread.Name); for (int i = 5; i < 10; i++) { Console.WriteLine( "T2 state [{0}], T1 state [{1}], CurrentThreadName={2} showing {3}", T2.ThreadState, T1.ThreadState, Thread.CurrentThread.Name, i.ToString()); } Console.WriteLine( "T2 state [{0}], T1 state [{1}], CurrentThreadName={2}", T2.ThreadState, T1.ThreadState, Thread.CurrentThread.Name); } } }

程序运行结果:


2.Sleep方法挂起当前的线程,也就是说在给定的时间内当前线程得不到运行的机会(cpu的时间片)

示例:

using System; using System.Threading; namespace ThreadSleep { class Program { public static Thread T1; public static Thread T2; public static void Main(string[] args) { Console.WriteLine("Enter Main method"); T1 = new Thread(new ThreadStart(Count1)); T2 = new Thread(new ThreadStart(Count2)); T1.Start(); T2.Start(); Console.WriteLine("Exit Main method"); Console.ReadLine(); } //thread T1 threadStart private static void Count1() { Console.WriteLine("Enter T1 counter"); for (int i = 0; i < 50; i++) { Console.Write(i + " "); if (i == 10) Thread.Sleep(1000); } Console.WriteLine("Exit T1 counter"); } //thread T2 threadStart private static void Count2() { Console.WriteLine("Enter T2 counter"); for (int i = 51; i < 100; i++) { Console.Write(i + " "); if (i == 70) Thread.Sleep(5000); } Console.WriteLine("Exit T2 counter"); } } }

上面的结果可以看出T1这个线程首先Start,然后是T2,之后T2进程输出了51和52,然后时间片到达,转向T1,T1开始运行,在运行过程中遇到10的话就sleep,这时T1进入WaitSleepJoin状态,此时T1得不到cpu的时间片,于是只能是T2运行,以此类推.....


3.Interrupt

当调用Sleep函数后,线程将进入WaitSleepJoin状态,此时如果想要重新唤醒该线程的话,那么可以使用Interrupt函数,但是需要注意:

"Interrupting a thread arbitrarily is dangerous, however, because any framework or third-party methods in the calling stack could unexpectedly receive the interrupt rather than your intended code. All it would take is for the thread to block briefly on a simple lock or synchronization resource, and any pending interruption would kick in. If the method wasn't designed to be interrupted (with appropriate cleanup code in finally blocks), objects could be left in an unusable state, or resources incompletely released.

Interrupting a thread is safe when you know exactly where the thread is."

测试代码如下:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ThreadInterrupt { class Program { public static Thread sleeper; public static Thread waker; public static void Main(string[] args) { Console.WriteLine("Enter Main method"); sleeper = new Thread(new ThreadStart(PutThreadToSleep)); waker = new Thread(new ThreadStart(WakeThread)); sleeper.Start(); waker.Start(); Console.WriteLine("Exiting Main method"); Console.ReadLine(); } //thread sleeper threadStart private static void PutThreadToSleep() { for (int i = 0; i < 50; i++) { Console.Write(i + " "); if (i == 10 || i == 20 || i == 30) { try { Console.WriteLine("Sleep, Going to sleep at {0}", i.ToString()); Thread.Sleep(20); } catch (ThreadInterruptedException e) { Console.WriteLine("Forcibly "); } Console.WriteLine("woken"); } } } //thread waker threadStart private static void WakeThread() { for (int i = 51; i < 100; i++) { Console.Write(i + " "); if (sleeper.ThreadState == ThreadState.WaitSleepJoin) { Console.WriteLine("Interrupting sleeper"); sleeper.Interrupt(); } } } } }


4.Abort

Abort函数的使用时比较危险的,个人实际上不主张使用该函数。

"A blocked thread can also be forcibly released via its Abort method. This has an effect similar to calling Interrupt, except that a ThreadAbortException is thrown instead of a ThreadInterruptedException. Furthermore, the exception will be re-thrown at the end of the catch block (in an attempt to terminate the thread for good) unless Thread.ResetAbort is called within the catch block. In the interim, the thread has a ThreadState of AbortRequested.

The big difference, though, between Interrupt and Abort is what happens when it's called on a thread that is not blocked. While Interrupt waits until the thread next blocks before doing anything, Abort throws an exception on the thread right where it's executing - maybe not even in your code. Aborting a non-blocked thread can have significant consequences."

-- Threading in C#, Joseph Albahari.

下面这个示例将展示如何创建线程的Start, Pause, Resume等操作。

class provides a background worker that finds prime numbers, that /// are reported to the UI via the ReportWorkDone event. The UI may pause /// the worker by calling the Pause() method, and may resume the worker by /// calling the Resume() method. The UI may also cancel the worker by setting /// the ReportWorkDone events event args Cancel property to true. /// </summary> public class WorkerThread { private Thread worker; public event ReportWorkDoneEventhandler ReportWorkDone; private volatile bool cancel = false; private ManualResetEvent trigger = new ManualResetEvent(true); //ctor public WorkerThread() { } //Do the work, start the thread public void Start(long primeNumberLoopToFind) { worker = new Thread(new ParameterizedThreadStart(DoWork)); worker.Start(primeNumberLoopToFind); } //Thread start method private void DoWork(object data) { long primeNumberLoopToFind = (long)data; int divisorsFound = 0; int startDivisor = 1; for (int i = 0; i < primeNumberLoopToFind; i++) { //wait for trigger trigger.WaitOne(); divisorsFound = 0; startDivisor = 1; //check for prime numbers, and if we find one raise //the ReportWorkDone event while (startDivisor <= i) { if (i % startDivisor == 0) divisorsFound++; startDivisor++; } if (divisorsFound == 2) { WorkDoneCancelEventArgs e = new WorkDoneCancelEventArgs(i); OnReportWorkDone(e); cancel = e.Cancel; //check whether thread should carry on, //perhaps user cancelled it if (cancel) return; } } } /// <summary> /// make the worker thread wait on the ManualResetEvent /// </summary> public void Pause() { trigger.Reset(); } /// <summary> /// signal the worker thread, raise signal on /// the ManualResetEvent /// </summary> public void Resume() { trigger.Set(); } /// <summary> /// Raise the ReportWorkDone event /// </summary> protected virtual void OnReportWorkDone(WorkDoneCancelEventArgs e) { if (ReportWorkDone != null) { ReportWorkDone(this, e); } } } //Simple cancellable EventArgs, that also exposes //current prime number found to UI public class WorkDoneCancelEventArgs : CancelEventArgs { public int PrimeFound { get; private set; } public WorkDoneCancelEventArgs(int primeFound) { this.PrimeFound = primeFound; } } }

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; namespace ThreadResumePause_StopUsingEventArgs { public partial class Form1 : Form { private WorkerThread wt = new WorkerThread(); private SynchronizationContext context; private bool primeThreadCancel = false; public Form1() { InitializeComponent(); //obtain the current SynchronizationContext context = SynchronizationContext.Current; } void wt_ReportWorkDone(object sender, WorkDoneCancelEventArgs e) { //+++++++++++++++++++++++++++++++++++++++++++++++++++++ //NOTE : This would also work to marshal call to UI thread //+++++++++++++++++++++++++++++++++++++++++++++++++++++ //this.Invoke(new EventHandler(delegate //{ // lstItems.Items.Add(e.PrimeFound.ToString()); //})); //marshal call to UI thread context.Post(new SendOrPostCallback(delegate(object state) { this.lstItems.Items.Add(e.PrimeFound.ToString()); }), null); //should worker thread be caneclled, has user clicked cancel button? e.Cancel = primeThreadCancel; } private void btnStart_Click(object sender, EventArgs e) { //start the worker and listen to its ReportWorkDone event wt.Start(100000); wt.ReportWorkDone += new ReportWorkDoneEventhandler(wt_ReportWorkDone); primeThreadCancel= false; } private void btnCancel_Click(object sender, EventArgs e) { primeThreadCancel= true; } private void btnPause_Click(object sender, EventArgs e) { wt.Pause(); } private void btnResume_Click(object sender, EventArgs e) { wt.Resume(); } } }

using System; using System.ComponentModel; using System.Threading; namespace ThreadResumePause_StopUsingEventArgs { public delegate void ReportWorkDoneEventhandler(object sender, WorkDoneCancelEventArgs e); /// <summary> /// This class provides a background worker that finds prime numbers, that /// are reported to the UI via the ReportWorkDone event. The UI may pause /// the worker by calling the Pause() method, and may resume the worker by /// calling the Resume() method. The UI may also cancel the worker by setting /// the ReportWorkDone events event args Cancel property to true. /// </summary> public class WorkerThread { private Thread worker; public event ReportWorkDoneEventhandler ReportWorkDone; private volatile bool cancel = false; private ManualResetEvent trigger = new ManualResetEvent(true); //ctor public WorkerThread() { } //Do the work, start the thread public void Start(long primeNumberLoopToFind) { worker = new Thread(new ParameterizedThreadStart(DoWork)); worker.Start(primeNumberLoopToFind); } //Thread start method private void DoWork(object data) { long primeNumberLoopToFind = (long)data; int divisorsFound = 0; int startDivisor = 1; for (int i = 0; i < primeNumberLoopToFind; i++) { //wait for trigger trigger.WaitOne(); divisorsFound = 0; startDivisor = 1; //check for prime numbers, and if we find one raise //the ReportWorkDone event while (startDivisor <= i) { if (i % startDivisor == 0) divisorsFound++; startDivisor++; } if (divisorsFound == 2) { WorkDoneCancelEventArgs e = new WorkDoneCancelEventArgs(i); OnReportWorkDone(e); cancel = e.Cancel; //check whether thread should carry on, //perhaps user cancelled it if (cancel) return; } } } /// <summary> /// make the worker thread wait on the ManualResetEvent /// </summary> public void Pause() { trigger.Reset(); } /// <summary> /// signal the worker thread, raise signal on /// the ManualResetEvent /// </summary> public void Resume() { trigger.Set(); } /// <summary> /// Raise the ReportWorkDone event /// </summary> protected virtual void OnReportWorkDone(WorkDoneCancelEventArgs e) { if (ReportWorkDone != null) { ReportWorkDone(this, e); } } } //Simple cancellable EventArgs, that also exposes //current prime number found to UI public class WorkDoneCancelEventArgs : CancelEventArgs { public int PrimeFound { get; private set; } public WorkDoneCancelEventArgs(int primeFound) { this.PrimeFound = primeFound; } } }

其中需要注意下面几点:

1.如何向一个线程启动时,传递参数?

worker = new Thread(new ParameterizedThreadStart(DoWork)); worker.Start(primeNumberLoopToFind);

2.如何暂停一个线程?

private ManualResetEvent trigger = new ManualResetEvent(true);

for (int i = 0; i< primeNumberLoopToFind; i++) { //wait for trigger trigger.WaitOne();

trigger.Reset();

3.如何恢复一个线程?

trigger.Set();

4.示例中如何停止线程?

示例中线程的停止其实是让该worker thread运行完毕实现的。

if (divisorsFound == 2) { WorkDoneCancelEventArgs e = new WorkDoneCancelEventArgs(i); OnReportWorkDone(e); cancel = e.Cancel; //check whether thread should carry on, //perhaps user cancelled it if (cancel) return; }


参考文献和示例代码下载:

http://www.codeproject.com/KB/threads/ThreadingDotNet2.aspx

代码下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值