重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock

时间:2022-12-27 10:02:48

[源码下载]

重新想象 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

<Page
x:Class="XamlDemo.Thread.Lock.LockDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Thread.Lock"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> <Grid Background="Transparent">
<StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsgWithoutLock" FontSize="14.667" />
<TextBlock Name="lblMsgWithLock" FontSize="14.667" /> </StackPanel>
</Grid>
</Page>

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<Task> tasks = new List<Task>(); // 一共 100 个任务并行执行,每个任务均累加同一个静态变量 100000 次,以模拟并发访问静态变量的场景
for (int i = ; i < ; i++)
{
Task task = Task.Run(
() =>
{
/******************有锁的逻辑开始******************/
try
{
// 通过 lock 锁住指定的对象以取得排它锁,在 lock 区域内的代码执行完毕后释放排它锁,排它锁释放之前其它进入到此的线程会排队等候
lock (_objLock)
{
for (int j = ; j < ; j++)
{
_countWithLock++;
}
}
}
finally { }
/******************有锁的逻辑结束******************/ /******************没锁的逻辑开始******************/
for (int j = ; j < ; j++)
{
_countWithoutLock++;
}
/******************没锁的逻辑结束******************/
}); tasks.Add(task);
} // 等待所有任务执行完毕
await Task.WhenAll(tasks); lblMsgWithoutLock.Text = "计数器(不带锁)结果:" + _countWithoutLock.ToString();
lblMsgWithLock.Text = "计数器(带锁)结果:" + _countWithLock.ToString();
}
}
}

2、演示 Monitor 的使用
Thread/Lock/MonitorDemo.xaml

<Page
x:Class="XamlDemo.Thread.Lock.MonitorDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Thread.Lock"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> <Grid Background="Transparent">
<StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsg" FontSize="14.667" /> </StackPanel>
</Grid>
</Page>

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 = ; i < ; 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 = ; i < ; 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

<Page
x:Class="XamlDemo.Thread.Lock.InterlockedDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Thread.Lock"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> <Grid Background="Transparent">
<StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsgWithoutLock" FontSize="14.667" />
<TextBlock Name="lblMsgWithLock" FontSize="14.667" /> </StackPanel>
</Grid>
</Page>

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<Task> tasks = new List<Task>(); // 一共 100 个任务并行执行,每个任务均累加同一个静态变量 100000 次,以模拟并发访问静态变量的场景
for (int i = ; i < ; i++)
{
Task task = Task.Run(
() =>
{
/******************有锁的逻辑开始******************/
for (int j = ; j < ; j++)
{
// 原子方式让 _countWithLock 加 1
Interlocked.Increment(ref _countWithLock);
}
/******************有锁的逻辑结束******************/ /******************没锁的逻辑开始******************/
for (int j = ; j < ; j++)
{
_countWithoutLock++;
}
/******************没锁的逻辑结束******************/
}); tasks.Add(task);
} await Task.WhenAll(tasks); lblMsgWithoutLock.Text = "计数器(不带锁)结果:" + _countWithoutLock.ToString();
lblMsgWithLock.Text = "计数器(带锁)结果:" + _countWithLock.ToString();
}
}
}

4、演示 Mutex 的使用
Thread/Lock/MutexDemo.xaml

<Page
x:Class="XamlDemo.Thread.Lock.MutexDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Thread.Lock"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> <Grid Background="Transparent">
<StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsgWithoutLock" FontSize="14.667" />
<TextBlock Name="lblMsgWithLock" FontSize="14.667" /> </StackPanel>
</Grid>
</Page>

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<Task> tasks = new List<Task>(); // 一共 100 个任务并行执行,每个任务均累加同一个静态变量 100000 次,以模拟并发访问静态变量的场景
for (int i = ; i < ; i++)
{
Task task = Task.Run(
() =>
{
/******************有锁的逻辑开始******************/
// 当前线程拿到 Mutex,阻塞当前线程,可以指定阻塞的超时时间
_mutex.WaitOne(); for (int j = ; j < ; j++)
{
_countWithLock++;
} // 释放 Mutex
_mutex.ReleaseMutex();
/******************有锁的逻辑结束******************/ /******************没锁的逻辑开始******************/
for (int j = ; j < ; j++)
{
_countWithoutLock++;
}
/******************没锁的逻辑结束******************/
}); tasks.Add(task);
} await Task.WhenAll(tasks); lblMsgWithoutLock.Text = "计数器(不带锁)结果:" + _countWithoutLock.ToString();
lblMsgWithLock.Text = "计数器(带锁)结果:" + _countWithLock.ToString();
}
}
}

5、演示 ReaderWriterLockSlim 的使用
Thread/Lock/ReaderWriterLockDemo.xaml

<Page
x:Class="XamlDemo.Thread.Lock.ReaderWriterLockDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Thread.Lock"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> <Grid Background="Transparent">
<StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsgForRead" FontSize="14.667" />
<TextBlock Name="lblMsgForWrite" FontSize="14.667" /> </StackPanel>
</Grid>
</Page>

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()); ThreadPoolTimer.CreatePeriodicTimer(
(timer) =>
{
// 进入写锁
_rwLock.EnterWriteLock(); new ManualResetEvent(false).WaitOne(); // 本线程停 3000 毫秒
OutMsgForWrite("写:" + DateTime.Now.ToString("mm:ss.fff")); // 离开写锁
_rwLock.ExitWriteLock();
},
TimeSpan.FromMilliseconds());
} 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
[源码下载]

重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock的更多相关文章

  1. 重新想象 Windows 8 Store Apps &lpar;47&rpar; - 多线程之线程同步&colon; Semaphore&comma; CountdownEvent&comma; Barrier&comma; ManualResetEvent&comma; AutoResetEvent

    [源码下载] 重新想象 Windows 8 Store Apps (47) - 多线程之线程同步: Semaphore, CountdownEvent, Barrier, ManualResetEve ...

  2. 重新想象 Windows 8 Store Apps &lpar;42&rpar; - 多线程之线程池&colon; 延迟执行&comma; 周期执行&comma; 在线程池中找一个线程去执行指定的方法

    [源码下载] 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法 作者:webabcd 介绍重新想象 Wi ...

  3. 重新想象 Windows 8 Store Apps &lpar;43&rpar; - 多线程之任务&colon; Task 基础&comma; 多任务并行执行&comma; 并行运算(Parallel)

    [源码下载] 重新想象 Windows 8 Store Apps (43) - 多线程之任务: Task 基础, 多任务并行执行, 并行运算(Parallel) 作者:webabcd 介绍重新想象 W ...

  4. 重新想象 Windows 8 Store Apps &lpar;44&rpar; - 多线程之异步编程&colon; 经典和最新的异步编程模型&comma; IAsyncInfo 与 Task 相互转换

    [源码下载] 重新想象 Windows 8 Store Apps (44) - 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换 作者:webabcd 介绍 ...

  5. 重新想象 Windows 8 Store Apps &lpar;45&rpar; - 多线程之异步编程&colon; IAsyncAction&comma; IAsyncOperation&comma; IAsyncActionWithProgress&comma; IAsyncOperationWithProgress

    [源码下载] 重新想象 Windows 8 Store Apps (45) - 多线程之异步编程: IAsyncAction, IAsyncOperation, IAsyncActionWithPro ...

  6. 重新想象 Windows 8 Store Apps &lpar;48&rpar; - 多线程之其他辅助类&colon; SpinWait&comma; SpinLock&comma; Volatile&comma; SynchronizationContext&comma; CoreDispatcher&comma; ThreadLocal&comma; ThreadStaticAttribute

    [源码下载] 重新想象 Windows 8 Store Apps (48) - 多线程之其他辅助类: SpinWait, SpinLock, Volatile, SynchronizationCont ...

  7. 重新想象 Windows 8 Store Apps 系列文章索引

    [源码下载][重新想象 Windows 8.1 Store Apps 系列文章] 重新想象 Windows 8 Store Apps 系列文章索引 作者:webabcd 1.重新想象 Windows ...

  8. 重新想象 Windows 8 Store Apps &lpar;34&rpar; - 通知&colon; Toast Demo&comma; Tile Demo&comma; Badge Demo

    [源码下载] 重新想象 Windows 8 Store Apps (34) - 通知: Toast Demo, Tile Demo, Badge Demo 作者:webabcd 介绍重新想象 Wind ...

  9. 重新想象 Windows 8 Store Apps &lpar;36&rpar; - 通知&colon; Tile 详解

    [源码下载] 重新想象 Windows 8 Store Apps (36) - 通知: Tile 详解 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 通知 Tile ...

随机推荐

  1. C&num;设计模式系列:简单工厂模式(Simple Factory)

    1. 简单工厂模式简介 1.1 定义 简单工厂模式定义一个Factory类,可以根据参数的不同返回不同类的实例,被创建的实例通常有共同的父类. 简单工厂模式只需要一个Factory类. 简单工厂模式又 ...

  2. iOS开发——UI进阶篇(十三)UITabBarController简单使用,qq主流框架

    一.UITabBarController简单使用 // 程序加载完毕 - (BOOL)application:(UIApplication *)application didFinishLaunchi ...

  3. Positive-definite matrix

    In linear algebra, a symmetric n × n real matrix M is said to be positive definite if zTMz is positi ...

  4. Centos GPG key retrieval failed&colon; &lbrack;Errno 14&rsqb; Could not open&sol;read file&colon;&sol;&sol;&sol;etc&sol;pki&sol;rpm-gpg&sol;RPM-GPG-KEY-EPEL

    warning: rpmts_HdrFromFdno: Header V3 RSA/SHA256 Signature, key ID 0608b895: NOKEYRetrieving key fro ...

  5. jquery导航动画

    经常在网上看到的,鼠标在导航上移动时,导航底部的横条会自动移动到鼠标悬浮的导航项上. 效果如下图: 利用jquery的 animate 函数,很好实现.代码很简单! 代码如下: <!DOCTYP ...

  6. java08 Set

    Set: 无序不可重复,重复则覆盖,判断是不是重复也是通过equals方法判断的.HashSet和TreeSet,HashSet底层是HashMap. public static void main( ...

  7. AIM Tech Round 3 &lpar;Div&period; 2&rpar; B 数学&plus;贪心

    http://codeforces.com/contest/709 题目大意:给一个一维的坐标轴,上面有n个点,我们刚开始在位置a,问,从a点开始走,走n-1个点所需要的最小路程. 思路:我们知道,如 ...

  8. 【DG】&lbrack;三思笔记&rsqb;一步一步学DataGuard

    [DG][三思笔记]一步一步学DataGuard 它有无数个名字,有人叫它dg,有人叫它数据卫士,有人叫它data guard,在oracle的各项特性中它有着举足轻理的地位,它就是(掌声)..... ...

  9. 批量实现多台服务器之间ssh无密码登录的相互信任关系

    最近IDC上架了一批hadoop大数据业务服务器,由于集群环境需要在这些服务器之间实现ssh无密码登录的相互信任关系.具体的实现思路:在其中的任一台服务器上通过"ssh-keygen -t ...

  10. Butter Knife 使用方法

    获取控件 @InjectView(R.id.image_show_password)ImageView image_show_password; 控件事件 @OnClick(R.id.btn_subm ...