| 
 | 
	
 
 
  [源码下载] 
 
 
 
 
重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock   
作者:webabcd 
 
介绍 
重新想象 Windows 8 Store Apps 之 线程同步 
 
 
- lock - 其实就是对 Monitor.Enter() 和 Monitor.Exit() 的一个封装
 
 - Monitor - 锁
 
 - Interlocked - 为多个线程共享的数字型变量提供原子操作
 
 - Mutex - 互斥锁,主要用于同一系统内跨进程的互斥锁
 
 - ReaderWriterLock - 读写锁
 
     
示例 
1、演示 lock 的使用 
Thread/Lock/LockDemo.xaml 
 
 
 
 
 
 
 
 
 
 
 
  Thread/Lock/LockDemo.xaml.cs 
 
 
 
/* 
* 演示 lock 的使用 
*  
* 注:lock 其实就是对 Monitor.Enter() 和 Monitor.Exit() 的一个封装 
*/ 
using System.Collections.Generic; 
using System.Threading.Tasks; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Navigation; 
namespace XamlDemo.Thread.Lock 
{ 
public sealed partial class LockDemo : Page 
{ 
// 需要被 lock 的对象 
private static readonly object _objLock = new object(); 
private static int _countWithoutLock; 
private static int _countWithLock; 
public LockDemo() 
{ 
this.InitializeComponent(); 
} 
protected async override void OnNavigatedTo(NavigationEventArgs e) 
{ 
List tasks = new List(); 
// 一共 100 个任务并行执行,每个任务均累加同一个静态变量 100000 次,以模拟并发访问静态变量的场景 
for (int i = 0; i < 100; i++) 
{ 
Task task = Task.Run( 
() => 
{ 
/******************有锁的逻辑开始******************/ 
try 
{ 
// 通过 lock 锁住指定的对象以取得排它锁,在 lock 区域内的代码执行完毕后释放排它锁,排它锁释放之前其它进入到此的线程会排队等候 
lock (_objLock) 
{ 
for (int j = 0; j < 100000; j++) 
{ 
_countWithLock++; 
} 
} 
} 
finally { } 
/******************有锁的逻辑结束******************/ 
 
/******************没锁的逻辑开始******************/ 
for (int j = 0; j < 100000; j++) 
{ 
_countWithoutLock++; 
} 
/******************没锁的逻辑结束******************/ 
}); 
tasks.Add(task); 
} 
// 等待所有任务执行完毕 
await Task.WhenAll(tasks); 
lblMsgWithoutLock.Text = "计数器(不带锁)结果:" + _countWithoutLock.ToString(); 
lblMsgWithLock.Text = "计数器(带锁)结果:" + _countWithLock.ToString(); 
} 
} 
} 
   
2、演示 Monitor 的使用 
Thread/Lock/MonitorDemo.xaml 
 
 
 
 
 
 
 
 
 
 
  Thread/Lock/MonitorDemo.xaml.cs 
 
 
 
/* 
* 演示 Monitor 的使用 
*  
* 本例说明: 
* 由于 Task 基于线程池,所以 task1 和 task2 的启动顺序是不一定的,以下步骤假定 task1 先执行,task2 后执行 
* 1、task1 取得排它锁 
* 2、task1 Monitor.Wait() - 释放排它锁,然后 task1 进入等待队列,可以为其指定一个超时时间,超过则进入就绪队列 
* 3、task2 取得排它锁 
* 4、task2 Monitor.Pulse() - 让等待队列中的一个线程进入就绪队列(Monitor.PulseAll() 的作用是将等待队列中的全部线程全部放入就绪队列) 
* 5、task1 进入就绪队列 
* 6、task2 Monitor.Wait() - 释放排它锁,然后 task2 进入等待队列 
* 7、task1 取得排它锁 
* 8、以上步骤不断往复 
*  
* 注: 
* 1、Wait() 和 Pulse() 必须在 Enter() 和 Exit() 之间,或者在 lock(){ } 中 
* 2、只有就绪队列中的线程才能取得排它锁,等待队列中的线程是无法取得排它锁的 
*/ 
using System; 
using System.Collections.Generic; 
using System.Threading; 
using System.Threading.Tasks; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Navigation; 
namespace XamlDemo.Thread.Lock 
{ 
public sealed partial class MonitorDemo : Page 
{ 
// 需要被 lock 的对象 
private static readonly object _objLock = new object(); 
public MonitorDemo() 
{ 
this.InitializeComponent(); 
} 
protected async override void OnNavigatedTo(NavigationEventArgs e) 
{ 
string result = ""; 
// 在 task1 中执行则为 true,在 task2 中执行则为 false 
bool flag = true; 
Task task1 = Task.Run( 
() => 
{ 
try 
{ 
// 在指定的对象上取得排它锁 
                        Monitor.Enter(_objLock); 
for (int i = 0; i < 10; i++) 
{ 
if (flag) 
Monitor.Wait(_objLock);  
flag = true; 
result += string.Format("task1 i:{0}, taskId:{1}", i, Task.CurrentId); 
result += Environment.NewLine; 
Monitor.Pulse(_objLock); 
} 
} 
finally 
{ 
// 在指定的对象上释放排它锁 
                        Monitor.Exit(_objLock); 
} 
}); 
Task task2 = Task.Run( 
() => 
{ 
try 
{ 
// 在指定的对象上取得排它锁 
                        Monitor.Enter(_objLock); 
for (int i = 0; i < 10; i++) 
{ 
if (!flag) 
Monitor.Wait(_objLock); 
flag = false; 
result += string.Format("task2 i:{0}, taskId:{1}", i, Task.CurrentId); 
result += Environment.NewLine; 
Monitor.Pulse(_objLock); 
} 
} 
finally 
{ 
// 在指定的对象上释放排它锁 
                        Monitor.Exit(_objLock); 
} 
}); 
await Task.WhenAll(task1, task2); 
lblMsg.Text = result; 
} 
} 
} 
   
3、演示 Interlocked 的使用 
Thread/Lock/InterlockedDemo.xaml 
 
 
 
 
 
 
 
 
 
 
 
  Thread/Lock/InterlockedDemo.xaml.cs 
 
 
 
/* 
* 演示 Interlocked 的使用 
*  
* Interlocked - 为多个线程共享的数字型变量提供原子操作,其提供了各种原子级的操作方法,如:增减变量、比较变量、指定变量的值 
*  
* 注: 
* long Read(ref long location) - 用于在 32 位系统上以原子方式读取 64 位值(32 位系统访问 32 位值本身就是原子的,64 位系统访问 64 位值本身就是原子的) 
*/ 
using System.Collections.Generic; 
using System.Threading; 
using System.Threading.Tasks; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Navigation; 
namespace XamlDemo.Thread.Lock 
{ 
public sealed partial class InterlockedDemo : Page 
{ 
private static int _countWithoutLock; 
private static int _countWithLock; 
public InterlockedDemo() 
{ 
this.InitializeComponent(); 
} 
protected async override void OnNavigatedTo(NavigationEventArgs e) 
{ 
List tasks = new List(); 
// 一共 100 个任务并行执行,每个任务均累加同一个静态变量 100000 次,以模拟并发访问静态变量的场景 
for (int i = 0; i < 100; i++) 
{ 
Task task = Task.Run( 
() => 
{ 
/******************有锁的逻辑开始******************/ 
for (int j = 0; j < 100000; j++) 
{ 
// 原子方式让 _countWithLock 加 1 
Interlocked.Increment(ref _countWithLock); 
} 
/******************有锁的逻辑结束******************/ 
 
/******************没锁的逻辑开始******************/ 
for (int j = 0; j < 100000; j++) 
{ 
_countWithoutLock++; 
} 
/******************没锁的逻辑结束******************/ 
}); 
tasks.Add(task); 
} 
await Task.WhenAll(tasks); 
lblMsgWithoutLock.Text = "计数器(不带锁)结果:" + _countWithoutLock.ToString(); 
lblMsgWithLock.Text = "计数器(带锁)结果:" + _countWithLock.ToString(); 
} 
} 
} 
   
4、演示 Mutex 的使用 
Thread/Lock/MutexDemo.xaml 
 
 
 
 
 
 
 
 
 
 
 
  Thread/Lock/MutexDemo.xaml.cs 
 
 
 
/* 
* 演示 Mutex 的使用 
*  
* Mutex - 互斥锁,主要用于同一系统内跨进程的互斥锁 
*/ 
using System.Collections.Generic; 
using System.Threading; 
using System.Threading.Tasks; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Navigation; 
namespace XamlDemo.Thread.Lock 
{ 
public sealed partial class MutexDemo : Page 
{ 
private Mutex _mutex = new Mutex(); 
private static int _countWithoutLock; 
private static int _countWithLock; 
public MutexDemo() 
{ 
this.InitializeComponent(); 
} 
protected async override void OnNavigatedTo(NavigationEventArgs e) 
{ 
List tasks = new List(); 
// 一共 100 个任务并行执行,每个任务均累加同一个静态变量 100000 次,以模拟并发访问静态变量的场景 
for (int i = 0; i < 100; i++) 
{ 
Task task = Task.Run( 
() => 
{ 
/******************有锁的逻辑开始******************/ 
// 当前线程拿到 Mutex,阻塞当前线程,可以指定阻塞的超时时间 
                        _mutex.WaitOne();  
for (int j = 0; j < 100000; j++) 
{ 
_countWithLock++; 
} 
// 释放 Mutex 
                        _mutex.ReleaseMutex(); 
/******************有锁的逻辑结束******************/ 
 
/******************没锁的逻辑开始******************/ 
for (int j = 0; j < 100000; j++) 
{ 
_countWithoutLock++; 
} 
/******************没锁的逻辑结束******************/ 
}); 
tasks.Add(task); 
} 
await Task.WhenAll(tasks); 
lblMsgWithoutLock.Text = "计数器(不带锁)结果:" + _countWithoutLock.ToString(); 
lblMsgWithLock.Text = "计数器(带锁)结果:" + _countWithLock.ToString(); 
} 
} 
} 
   
5、演示 ReaderWriterLockSlim 的使用 
Thread/Lock/ReaderWriterLockDemo.xaml 
 
 
 
 
 
 
 
 
 
 
 
  Thread/Lock/ReaderWriterLockDemo.xaml.cs 
 
 
 
/* 
* 演示 ReaderWriterLockSlim 的使用 
*  
* ReaderWriterLock - 读写锁(WinRT 中不提供) 
* ReaderWriterLockSlim - 轻量级的 ReaderWriterLock 
*     支持进入/离开读锁,进入/离开写锁,读锁升级为写锁 
*     支持相关状态的获取,如:当前线程是否进入了读锁以及进入读锁的次数,是否进入了写锁以及进入写锁的次数,是否由读锁升级为了写锁以及由读锁升级为写锁的次数 
*  
* 注: 
* 1、每次可以有多个线程进入读锁 
* 2、每次只能有一个线程进入写锁 
* 3、进入写锁后,无法进入读锁 
*  
*  
* 本例模拟了一个“高频率读,低频率写”的场景 
*/ 
using System; 
using System.Threading; 
using Windows.System.Threading; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Navigation; 
namespace XamlDemo.Thread.Lock 
{ 
public sealed partial class ReaderWriterLockDemo : Page 
{ 
ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); 
public ReaderWriterLockDemo() 
{ 
this.InitializeComponent(); 
} 
protected override void OnNavigatedTo(NavigationEventArgs e) 
{ 
ThreadPoolTimer.CreatePeriodicTimer( 
(timer) => 
{ 
// 进入读锁 
                    _rwLock.EnterReadLock(); 
OutMsgForRead("读:" + DateTime.Now.ToString("mm:ss.fff")); 
// 离开读锁 
                    _rwLock.ExitReadLock(); 
}, 
TimeSpan.FromMilliseconds(100)); 
 
ThreadPoolTimer.CreatePeriodicTimer( 
(timer) => 
{ 
// 进入写锁 
                   _rwLock.EnterWriteLock(); 
new ManualResetEvent(false).WaitOne(3000); // 本线程停 3000 毫秒 
OutMsgForWrite("写:" + DateTime.Now.ToString("mm:ss.fff")); 
// 离开写锁 
                   _rwLock.ExitWriteLock(); 
}, 
TimeSpan.FromMilliseconds(5000)); 
} 
private async void OutMsgForRead(string msg) 
{ 
await Dispatcher.RunAsync( 
Windows.UI.Core.CoreDispatcherPriority.High, 
() => 
{ 
lblMsgForRead.Text = msg; 
}); 
} 
private async void OutMsgForWrite(string msg) 
{ 
await Dispatcher.RunAsync( 
Windows.UI.Core.CoreDispatcherPriority.High, 
() => 
{ 
lblMsgForWrite.Text = msg; 
}); 
} 
} 
} 
   
OK 
[源码下载] |   
 
 
 
 | 
  
 |