程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Windows 8 Store Apps學習(47) 多線程之線程同步: Semaphore等

Windows 8 Store Apps學習(47) 多線程之線程同步: Semaphore等

編輯:關於.NET

多線程之線程同步: Semaphore, CountdownEvent, Barrier, ManualResetEvent, AutoResetEvent

介紹

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

[源碼下載]:http://files.cnblogs.com/webabcd/Windows8.rar

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved