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

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

編輯:關於.NET

多線程之線程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock

介紹

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

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

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