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

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

[源码下载]


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

你可能感兴趣的:(Semaphore)