多线程新手篇

由于winform的缘故,最近一周都在研究多线程,以前也看过多线程方面的资料,一个WaitOne就把我难倒了。呵呵,现在总算搞清楚了。

本片(参考自codeproject)主要讲以下内容:
(一).Sleep和Join的用法
(二).Invoke和BeginInvoke的使用及区别
(三).Monitor类的使用
(四).AutoResetEvent使用

(一)1.Sleep()方法,调用后,线程会被阻止指定的时间,时间到了后,会继续执行。
线程需引用using System.Threading;命名空间。

Code

2.Join()方法,肯定有两个线程,Join才有用。
比如两个线程T1,T2
你在T2里写上T1.Join()的话,在执行的时候,T2会被Block,直到T1是的状态是stopped。

Code

(二).Invoke和BeginInvoke

Code

由于程序的并行执行,所以会交替输出。

Code

这个输出和上面输出差不多,也是交替输出的。

Code

BeginInvoke()的返回值是IAsyncResult类型的,表示dddddddddddddddd
EndInvoke()可以获得返回值。

Code

 

Winform中的多线程与UI

Code

大家看到上面这段代码没任何问题,就是往窗体上面添加个TextBox控件。

Code

大家再看这段代码,貌似也没有问题,但是运行的时候,就会抛出异常。
线程间操作无效: 从不是创建控件“Form2”的线程访问它。
出错的原因在于,主线程创建了form窗体,别的线程是不能操作它的。

 

Code

此处首先声明了委托MyDelegate。
 this.Invoke(delInstance); 中的this代表的是form对象,实际上还是主线程执行的AddControl
Invoke方法,会阻塞别的线程,直到自己的调用返回了,才继续往下执行,就是说Invoke()调用后会立即返回。
BeginInvoke就不会阻塞别的线程。这是二者的区别之一。

 

Code

上面的代码中,我们没必要用Invoke方法,因为我们是在主线程中,主线程中可以直接更新UI的。但是在一些情况下,我们不知道是否个别方法是在主线程里还是别的线程里执行的,并且,调用者不知道是否个别方法有更新UI的代码。所以,如果更新UI的话,应该切换到主线程里去执行。
其实没那么麻烦,InvokeRequired属性就是为了这个目的,如果当前线程不是主线程,InvokeRequired就返回true,是主线程就返回false。因此,任何更新UI的代码应该先判断InvokeRequired。

 

Code

 

(三).Monitor.Wait()方法,msdn解释:当前拥有指定对象上的锁的线程调用此方法以释放该对象,以便其他线程可以访问它。调用方在等待重新获取锁期间被阻止。当调用方需要等待另一个线程操作导致的状态更改时,将调用此方法。

当线程调用 Wait 时,它释放对象的锁并进入对象的等待队列。对象的就绪队列中的下一个线程(如果有)获取锁并拥有对对象的独占使用。所有调用 Wait 的线程都将留在等待队列中,直到它们接收到由锁的所有者发送的 Pulse 或 PulseAll 的信号为止。如果发送了 Pulse,则只影响位于等待队列最前面的线程。如果发送了 PulseAll,则将影响正等待该对象的所有线程。接收到信号后,一个或多个线程将离开等待队列而进入就绪队列。就绪队列中的线程被允许重新获取锁。

当调用线程重新获取对象上的锁后,此方法将返回。请注意,如果锁的持有者不调用 Pulse 或 PulseAll,则此方法将无限期地阻止。

调用方执行一次 Wait,与已为指定对象调用 Enter 的次数无关。概念上,Wait 方法存储调用方对对象调用 Enter 的次数,并按完全释放锁定对象所需要的次数调用 Exit。然后调用方在等待重新获取对象期间被阻止。当调用方重新获取锁时,系统按还原调用方的已保存 Enter 计数所需要的次数调用 Enter。调用 Wait 仅释放指定对象的锁;如果调用方是其他对象的锁的所有者,则不释放这些锁。

(四)

Code

 

Code

 

 Wait示例

Wait
private static object lockObject = new object();

static void Main(string[] args)
{
Console.WriteLine(
"主线程运行,线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());
Thread t
= new Thread(DoWork);
t.Start();
Monitor.Enter(lockObject);
Console.WriteLine(
"主线程得到锁,开始运行");

Console.WriteLine(
"主线程释放锁,开始等待");
Monitor.Wait(lockObject);
Console.WriteLine(
"主线程重新得到锁,结束等待");//这句得等到worker线程pulse之后才能执行


Console.Read();
}

static void DoWork()
{
Console.WriteLine(
"worker线程运行,线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());
Console.WriteLine(
"停顿10秒");
int i = 1;
while (i <= 10)
{
Console.WriteLine(i.ToString());
Thread.Sleep(
1000);
i
++;
if (i == 5)
{
Monitor.Enter(lockObject);
Monitor.Pulse(lockObject);
Monitor.Exit(lockObject);
}
}
}

 买书示例:

代码
下面我们来举一个例子:我去书店买书,当我选中一本书后我会去收费处付钱,
付好钱后再去仓库取书。这个顺序不能颠倒,我作为主线程,收费处和仓库做两个辅助线程,代码如下:

using System;
using System.Linq;
using System.Activities;
using System.Activities.Statements;
using System.Threading;

namespace CaryAREDemo
{
class Me
{
const int numIterations = 550;
static AutoResetEvent myResetEvent = new AutoResetEvent(false);
static AutoResetEvent ChangeEvent = new AutoResetEvent(false);
//static ManualResetEvent myResetEvent = new ManualResetEvent(false);
//static ManualResetEvent ChangeEvent = new ManualResetEvent(false);
static int number; //这是关键资源

static void Main()
{
Thread payMoneyThread
= new Thread(new ThreadStart(PayMoneyProc));
payMoneyThread.Name
= "付钱线程";
Thread getBookThread
= new Thread(new ThreadStart(GetBookProc));
getBookThread.Name
= "取书线程";
payMoneyThread.Start();
getBookThread.Start();

for (int i = 1; i <= numIterations; i++)
{
Console.WriteLine(
"买书线程:数量{0}", i);
number
= i;
//Signal that a value has been written.
myResetEvent.Set();
ChangeEvent.Set();
Thread.Sleep(
0);
}
payMoneyThread.Abort();
getBookThread.Abort();
}

static void PayMoneyProc()
{
while (true)
{
myResetEvent.WaitOne();
//myResetEvent.Reset();
Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number);
}
}
static void GetBookProc()
{
while (true)
{
ChangeEvent.WaitOne();
// ChangeEvent.Reset();
Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number);
Console.WriteLine(
"------------------------------------------");
Thread.Sleep(
0);
}
}
}
}
运行结果如下:

 

posted on 2009-07-26 19:32  几度夕阳红了  阅读(374)  评论(0编辑  收藏  举报