zoukankan      html  css  js  c++  java
  • 重新想象 Windows 8 Store Apps (47)

    [源码下载]


    重新想象 Windows 8 Store Apps (47) - 多线程之线程同步: Semaphore, CountdownEvent, Barrier, ManualResetEvent, AutoResetEvent



    作者:webabcd


    介绍
    重新想象 Windows 8 Store Apps 之 线程同步

    • Semaphore - 信号量
    • CountdownEvent - 通过信号数量实现线程同步
    • Barrier - 屏障
    • ManualResetEvent - 手动红绿灯
    • AutoResetEvent - 自动红绿灯



    示例
    1、演示 Semaphore 的使用
    Thread/Lock/SemaphoreDemo.xaml

    <Page
        x:Class="XamlDemo.Thread.Lock.SemaphoreDemo"
        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/SemaphoreDemo.xaml.cs

    /*
     * 演示 Semaphore 的使用
     * 
     * Semaphore - 信号量
     * SemaphoreSlim - 轻量级的 Semaphore
     * 
     * 注:
     * 直译 Semaphore 的话不太好理解,可以将 Semaphore 理解为一个许可证中心,该许可证中心的许可证数量是有限的
     * 线程想要执行就要先从许可证中心获取一个许可证(如果许可证中心的许可证已经发完了,那就等着,等着其它线程归还许可证),执行完了再还回去
     */
    
    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 SemaphoreDemo : Page
        {
            /*
             * Semaphore(int initialCount, int maximumCount, string name)
             *     initialCount - 许可证中心初始拥有的许可证数量,即初始情况下已经发出的许可证数量为 maximumCount - initialCount
             *     maximumCount - 许可证中心总共拥有的许可证数量
             *     name - 许可证中心的名称
             * Semaphore OpenExisting(string name) - 打开指定名称的许可证中心
             */
    
            // 实例化一个许可证中心,该中心拥有的许可证数量为 2 个
            private Semaphore _semaphore = new Semaphore(2, 2);
    
            public SemaphoreDemo()
            {
                this.InitializeComponent();
            }
    
            protected async override void OnNavigatedTo(NavigationEventArgs e)
            {
                List<Task> tasks = new List<Task>();
    
                // 模拟 5 个线程并行执行,拿到许可证的线程才能运行,而许可证中心只有 2 个许可证
                for (int i = 0; i < 5; i++)
                {
                    CancellationToken token = new CancellationTokenSource().Token;
    
                    Task task = Task.Run(
                        () =>
                        {
                            OutMsg(string.Format("task {0} 等待一个许可证", Task.CurrentId));
                            token.WaitHandle.WaitOne(5000);
    
                            // WaitOne() - 申请许可证
                            _semaphore.WaitOne();
                            OutMsg(string.Format("task {0} 申请到一个许可证", Task.CurrentId));
    
                            token.WaitHandle.WaitOne(1000);
    
                            OutMsg(string.Format("task {0} 归还了一个许可证", Task.CurrentId));
                            // int Release() - 归还许可证,返回值为:Release() 之前许可证中心可用的许可证数量
                            int ignored = _semaphore.Release();
                            // int Release(int releaseCount) - 指定释放的信号量的次数(按本文的理解就是指定归还的许可证数量)
                        },
                        token);
    
                    tasks.Add(task);
                }
    
                await Task.WhenAll(tasks);
            }
    
            private void OutMsg(string msg)
            {
                var ignored = Dispatcher.RunAsync(
                    Windows.UI.Core.CoreDispatcherPriority.High, 
                    () => 
                    {
                        lblMsg.Text += msg;
                        lblMsg.Text += Environment.NewLine;
                    });
            }
        }
    }


    2、演示 CountdownEvent 的使用
    Thread/Lock/CountdownEventDemo.xaml

    <Page
        x:Class="XamlDemo.Thread.Lock.CountdownEventDemo"
        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/CountdownEventDemo.xaml.cs

    /*
     * 演示 CountdownEvent 的使用
     * 
     * CountdownEvent - 通过信号数量实现线程同步
     */
    
    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 CountdownEventDemo : Page
        {
            private static int _count;
    
            public CountdownEventDemo()
            {
                this.InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                // 初始信号数量为 100 个
                using (CountdownEvent countdown = new CountdownEvent(100))
                {
                    // AddCount(), AddCount(int signalCount) - 增加 1 个信号,或增加指定数量的信号
                    // Reset(), Reset(int count) - 重置为初始的信号数量,或重置为指定的信号数量
                    // Signal(), Signal(int signalCount) - 减少 1 个信号,或减少指定数量的信号
                    // CurrentCount - 获取当前的信号数量
    
                    for (int i = 0; i < 100; i++)
                    {
                        Task task = Task.Run(
                            () =>
                            {
                                Interlocked.Increment(ref _count);
                                // 减少 1 个信号
                                countdown.Signal();
                            });
                    }
    
                    // 阻塞当前线程,直到 CountdownEvent 的信号数量变为 0
                    countdown.Wait();
    
                    lblMsg.Text = "count: " + _count.ToString();
                }
            }
        }
    }


    3、演示 Barrier 的使用
    Thread/Lock/BarrierDemo.xaml

    <Page
        x:Class="XamlDemo.Thread.Lock.BarrierDemo"
        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/BarrierDemo.xaml.cs

    /*
     * 演示 Barrier 的使用
     * 
     * Barrier - 屏障
     * 
     * 按如下方式理解:
     * 1、Participant - 参与者
     * 2、SignalAndWait() - 某一个参与者已经到达屏障了
     * 3、所有参与者都到达屏障后,屏障解除
     */
    
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.UI.Core;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    
    namespace XamlDemo.Thread.Lock
    {
        public sealed partial class BarrierDemo : Page
        {
            private static int _count;
    
            public BarrierDemo()
            {
                this.InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                // AddParticipant(), AddParticipants(int participantCount) - 增加 1 个参与者,或增加指定数量的参与者
                // RemoveParticipant(), RemoveParticipants(int participantCount) - 减少 1 个参与者,或减少指定数量的参与者
                // ParticipantCount - 获取参与者总数
                // ParticipantsRemaining - 尚未到达屏障的参与者总数
    
                Barrier barrier = new Barrier(
                    5, // 初始有 5 个参与者
                    (ctx) => // 屏障解除之后
                    {
                        var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.High,
                            () =>
                            {
                                lblMsg.Text = "count: " + _count.ToString();
                            });
                    });
    
                for (int i = 0; i < 5; i++)
                {
                    Task task = Task.Run(
                        () =>
                        {
                            Interlocked.Increment(ref _count);
                            // 某一个参与者已经到达屏障了
                            barrier.SignalAndWait();
                            // SignalAndWait(int millisecondsTimeout) - 指定一个超时时间
                            // SignalAndWait(CancellationToken cancellationToken) - 指定一个 CancellationToken
                        });
                }
            }
        }
    }


    4、演示 ManualResetEvent 的使用
    Thread/Lock/ManualResetEventDemo.xaml

    <Page
        x:Class="XamlDemo.Thread.Lock.ManualResetEventDemo"
        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/ManualResetEventDemo.xaml.cs

    /*
     * 演示 ManualResetEvent 的使用
     * 
     * ManualResetEvent - 手动红绿灯
     * ManualResetEventSlim - 轻量级的 ManualResetEvent
     */
    
    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.Foundation;
    using Windows.System.Threading;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    
    namespace XamlDemo.Thread.Lock
    {
        public sealed partial class ManualResetEventDemo : Page
        {
            // true - 指定初始状态为绿灯
            private ManualResetEvent _manualResetEvent = new ManualResetEvent(true);
    
            private static int _count = 0;
    
            public ManualResetEventDemo()
            {
                this.InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                ManualResetEvent sleep = new ManualResetEvent(false);
    
                Task tas = Task.Run(
                    () =>
                    {
                        while (true)
                        {
                            // WaitOne() - 判断:绿灯则进入,红灯则阻塞
                            _manualResetEvent.WaitOne();
    
                            /*
                             * WaitOne(1000) 
                             *     1、如果当前是绿灯则进入
                             *     2、如果当前是红灯则阻塞
                             *         a) 1000 毫秒之内收到 Set() 信号则进入
                             *         b) 1000 毫秒之后如果还没收到 Set() 信号则强行进入
                             */
    
                            IAsyncAction ignored = Windows.System.Threading.ThreadPool.RunAsync(
                                (threadPoolWorkItem) =>
                                {
                                    // 在当前线程 sleep 1000 毫秒(WinRT 中没有 Thread.Sleep() 了)
                                    sleep.WaitOne(1000);
    
                                    OutMsg(string.Format("count:{0}, time:{1}", ++_count, DateTime.Now.ToString("mm:ss")));
    
                                    // Set() - 发出绿灯信号,并设置为绿灯
                                    _manualResetEvent.Set();
    
                                },
                                WorkItemPriority.High);
    
                            // Reset() - 发出红灯信号,并设置为红灯
                            _manualResetEvent.Reset(); 
                        }
                    });
            }
    
            private void OutMsg(string msg)
            {
                var ignored = Dispatcher.RunAsync(
                    Windows.UI.Core.CoreDispatcherPriority.High,
                    () =>
                    {
                        lblMsg.Text = msg;
                    });
            }
        }
    }


    5、演示 AutoResetEvent 的使用
    Thread/Lock/AutoResetEventDemo.xaml

    <Page
        x:Class="XamlDemo.Thread.Lock.AutoResetEventDemo"
        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/AutoResetEventDemo.xaml.cs

    /*
     * 演示 AutoResetEvent 的使用
     * 
     * AutoResetEvent - 自动红绿灯
     * 
     * AutoResetEvent 和 ManualResetEvent 的区别在于:AutoResetEvent 在 WaitOne() 进入之后会自动 Reset()
     */
    
    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.Foundation;
    using Windows.System.Threading;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    
    namespace XamlDemo.Thread.Lock
    {
        public sealed partial class AutoResetEventDemo : Page
        {
            // true - 指定初始状态为绿灯
            private AutoResetEvent _autoResetEvent = new AutoResetEvent(true);
    
            private static int _count = 0;
    
            public AutoResetEventDemo()
            {
                this.InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                ManualResetEvent sleep = new ManualResetEvent(false);
    
                Task tas = Task.Run(
                    () =>
                    {
                        while (true)
                        {
                            // WaitOne() - 判断:绿灯则进入,红灯则阻塞,进入之后自动 Reset()
                            _autoResetEvent.WaitOne();
    
                            /*
                             * WaitOne(1000) 
                             *     1、如果当前是绿灯则进入,进入之后自动 Reset()
                             *     2、如果当前是红灯则阻塞
                             *         a) 1000 毫秒之内收到 Set() 信号则进入,进入之后自动 Reset()
                             *         b) 1000 毫秒之后如果还没收到 Set() 信号则强行进入,进入之后自动 Reset()
                             */
    
                            IAsyncAction ignored = Windows.System.Threading.ThreadPool.RunAsync(
                                (threadPoolWorkItem) =>
                                {
                                    // 在当前线程 sleep 1000 毫秒(WinRT 中没有 Thread.Sleep() 了)
                                    sleep.WaitOne(1000);
    
                                    OutMsg(string.Format("count:{0}, time:{1}", ++_count, DateTime.Now.ToString("mm:ss")));
    
                                    // Set() - 发出绿灯信号,并设置为绿灯
                                    _autoResetEvent.Set();
    
                                },
                                WorkItemPriority.High);
                        }
                    });
            }
    
            private void OutMsg(string msg)
            {
                var ignored = Dispatcher.RunAsync(
                    Windows.UI.Core.CoreDispatcherPriority.High,
                    () =>
                    {
                        lblMsg.Text = msg;
                    });
            }
        }
    }



    OK
    [源码下载]

  • 相关阅读:
    HttpWebRequest.GetRequestStream方法timeout的原因及解决办法
    C#随机函数random()典型用法集锦
    windows 2008 开启默认共享
    Window xp命令大全
    大并发处理解决方案
    库特Z配置
    SQL Server 返回了错误 21(设备未就绪。) 解决方法
    C# 执行bat批处理文件
    sql索引从入门到精通(十亿行数据测试报告)
    DataTable使用时的小问题
  • 原文地址:https://www.cnblogs.com/webabcd/p/3229552.html
Copyright © 2011-2022 走看看