您的位置:首页 > 其它

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

2011-01-24 15:46 387 查看

thread生命周期简介

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



StateDescription
Running
The thread has been started, it is not blocked, and there is no pending
ThreadAbortException
.
StopRequested
The thread is being requested to stop. This is for internal use only.
SuspendRequested
The thread is being requested to suspend.
Background
The thread is being executed as a background thread, as opposed to a foreground thread. This state is controlled by setting the
Thread.IsBackground
property.
Unstarted
The
Thread.Start
method has not been invoked on the thread.
Stopped
The 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.)

Suspended
The thread has been suspended.
AbortRequested
The
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

代码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: