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

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

[源码下载]


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

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

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

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

<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(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
[源码下载]

你可能感兴趣的:(windows)