多线程同步与锁
本次主要讨论的是lock,autoeventset,moniter
代码如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
private static AutoResetEvent autoReset = new AutoResetEvent(false);
static int countNum = 0; //计数器
static object lockobj = new object(); //静态锁对象
static void Main(string[] args)
{
// test AutoResetEvent and Lock object or static object begin
Thread thread1 = new Thread(new ParameterizedThreadStart(wirte1));
thread1.Start(1);
Thread thread2 = new Thread(wirte1);
thread2.Start(2);
//--- test end---
// test Monitor begin
//Thread thread3 = new Thread(wirte2);
//thread3.Start(3);
//Thread thread5 = new Thread(wirte2);
//thread5.Start(5);
// -- end ---
Thread thread4 = new Thread(new ThreadStart(wirte4));
thread4.Start();
Console.ReadLine();
}
public static void wirte1(object index)
{
autoReset.WaitOne(); //阻塞,直到收到信号
Console.WriteLine(index.ToString() + " enter lock before");
//lock (new object()) //这样锁可以一次只能一个线程进入锁定的代码块,但一次过后可以其它的线程的抢到
lock (lockobj) //锁定后只有一个线程进入直至块内代码执行完
{
Console.WriteLine(index.ToString() + " enter lock after");
while (countNum < 50)
{
Console.WriteLine(countNum.ToString() + " index:" + index.ToString());
Thread.Sleep(500);
//autoReset.Reset();
countNum++;
}
}
//autoReset.Set();
}
public static void wirte2(object index)
{
bool isrealse = false;
lock (lockobj)
{
Console.WriteLine(index.ToString() + " enter lock after");
while (countNum < 50)
{
if (isrealse)
{
Monitor.Wait(lockobj); //阻塞当前线程
}
Console.WriteLine(countNum.ToString() + " index:" + index.ToString());
Thread.Sleep(500);
//autoReset.Reset();
countNum++;
if (countNum > 27)
{
Monitor.PulseAll(lockobj); //取消阻塞,并且当前lock无效
}
if (countNum > 30)
{
isrealse = true;
}
}
}
}
public static void wirte3()
{
for (int i = 0; i < 30; i++)
{
Console.WriteLine(i.ToString() + " thread3");
Thread.Sleep(500);
}
}
public static void wirte4()
{
lock (lockobj)
{
for (int i = 0; i < 30; i++)
{
Console.WriteLine(i.ToString() + " thread4");
Thread.Sleep(500);
if (i > 25)
{
autoReset.Set(); //置信号为true,阻塞的线程可以运行
}
}
}
}
}
}
上图为线程1,2执行write1,被阻塞,直到线程4发出信号,线程1,2收到信号后取得执行权的线程可以运行
改下main
static void Main(string[] args)
{
// test AutoResetEvent and Lock object or static object begin
//Thread thread1 = new Thread(new ParameterizedThreadStart(wirte1));
//thread1.Start(1);
//Thread thread2 = new Thread(wirte1);
//thread2.Start(2);
//--- test end---
// test Monitor begin
Thread thread3 = new Thread(wirte2);
thread3.Start(3);
Thread thread5 = new Thread(wirte2);
thread5.Start(5);
// -- end ---
Thread thread4 = new Thread(new ThreadStart(wirte4));
thread4.Start();
Console.ReadLine();
}
上图为线程3,5执行write2,线程4执行wirte4,首先取得lock的先执行,如果线程4取得锁,则需等待其执行完,如果线程3,5先取得lock则到>30后则阻塞,但在>27时Monitor.PulseAll(lockobj); 已取消阻塞且lock已没起作用,所以 Monitor.Wait(lockobj);起不到阻塞作用(很大概率),如果write2只有一个线程执行,则到〉30时一定会阻塞
总结:
1 lock new object 只对当前有效,随后所有等待线程都有可能获得锁
2 lock static object 多个线程如是用同一对象锁,则先获取的运行,其它的等待
3 AutoResetEvent waitone阻塞,set释放信号,被阻塞的线程可以获得运行权
4 Monitor.PulseAll(lockobj); 取消阻塞,且当前lock释放
5 Monitor.Wait(lockobj); 阻塞当前线程,
以上是vs2008,win7下的测试结果,如果有发现有误的请指正,以免误导大家,多谢!