• 重新想象 Windows 8 Store Apps (46)


    [源码下载]


    重新想象 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
    [源码下载]

  • 相关阅读:
    Chrome截屏-截取当前页
    SecureCRT 工具分享
    mongodb在shutdown时报错:shutdown must run from localhost when running db without auth
    gdb如何实现info vtbl命令
    aspose.word 替换图片
    字节跳动校招+社招
    Flink日志输出配置
    Kafka高可用及高性能原因
    基于SAAS模式的客服云平台落地实践
    代码Recode
  • 原文地址:https://www.cnblogs.com/webabcd/p/3222164.html
Copyright © 2020-2023  润新知