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

    [源码下载]


    重新想象 Windows 8 Store Apps (48) - 多线程之其他辅助类: SpinWait, SpinLock, Volatile, SynchronizationContext, CoreDispatcher, ThreadLocal, ThreadStaticAttribute



    作者:webabcd


    介绍
    重新想象 Windows 8 Store Apps 之 多线程操作的其他辅助类

    • SpinWait - 自旋等待
    • SpinLock - 自旋锁
    • volatile - 必在内存
    • SynchronizationContext - 在指定的线程上同步数据
    • CoreDispatcher - 调度器,用于线程同步
    • ThreadLocal - 用于保存每个线程自己的数据
    • ThreadStaticAttribute - 所指定的静态变量对每个线程都是唯一的



    示例
    1、演示 SpinWait 的使用
    Thread/Other/SpinWaitDemo.xaml.cs

    /*
     * SpinWait - 自旋等待,一个低级别的同步类型。它不会放弃任何 cpu 时间,而是让 cpu 不停的循环等待
     * 
     * 适用场景:多核 cpu ,预期等待时间非常短(几微秒)
     * 本例只是用于描述 SpinWait 的用法,而不代表适用场景
     */
    
    using System;
    using System.Threading;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    
    namespace XamlDemo.Thread.Other
    {
        public sealed partial class SpinWaitDemo : Page
        {
            public SpinWaitDemo()
            {
                this.InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                lblMsg.Text = DateTime.Now.ToString("mm:ss.fff");
    
                SpinWait.SpinUntil(
                    () =>  // 以下条件成立时,结束等待
                    {
                        return false;
                    }
                    // 如果此超时时间过后指定的条件还未成立,则强制结束等待
                    ,1000);
    
                lblMsg.Text += Environment.NewLine;
                lblMsg.Text += DateTime.Now.ToString("mm:ss.fff");
    
                SpinWait.SpinUntil(
                    () => // 以下条件成立时,结束等待
                    {
                        return DateTime.Now.Second % 2 == 0;
                    });
    
                lblMsg.Text += Environment.NewLine;
                lblMsg.Text += DateTime.Now.ToString("mm:ss.fff");
            }
        }
    }


    2、演示 SpinLock 的使用
    Thread/Other/SpinLockDemo.xaml.cs

    /*
     * SpinLock - 自旋锁,一个低级别的互斥锁。它不会放弃任何 cpu 时间,而是让 cpu 不停的循环等待,直至锁变为可用为止
     * 
     * 适用场景:多核 cpu ,预期等待时间非常短(几微秒)
     * 本例只是用于描述 SpinLock 的用法,而不代表适用场景
     */
    
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    
    namespace XamlDemo.Thread.Other
    {
        public sealed partial class SpinLockDemo : Page
        {
            private static int _count;
    
            public SpinLockDemo()
            {
                this.InitializeComponent();
            }
    
            protected async override void OnNavigatedTo(NavigationEventArgs e)
            {
                SpinLock spinLock = new SpinLock();
    
                List<Task> tasks = new List<Task>();
    
                // 一共 100 个任务并行执行,每个任务均累加同一个静态变量 100000 次,以模拟并发访问静态变量的场景
                for (int i = 0; i < 100; i++)
                {
                    Task task = Task.Run(
                        () =>
                        {
                            bool lockTaken = false;
    
                            try
                            {
                                // IsHeld - 锁当前是否已由任何线程占用
                                // IsHeldByCurrentThread - 锁是否由当前线程占用
                                //     要获取 IsHeldByCurrentThread 属性,则 IsThreadOwnerTrackingEnabled 必须为 true,可以在构造函数中指定,默认就是 true
    
                                // 进入锁,lockTaken - 是否已获取到锁
                                spinLock.Enter(ref lockTaken);
    
                                for (int j = 0; j < 100000; j++)
                                {
                                    _count++;
                                }
                            }
                            finally
                            {
                                // 释放锁
                                if (lockTaken)
                                    spinLock.Exit();
                            }
                        });
    
                    tasks.Add(task);
                }
    
                // 等待所有任务执行完毕
                await Task.WhenAll(tasks);
    
                lblMsg.Text = "count: " + _count.ToString();
            }
        }
    }


    3、演示 volatile 的使用
    Thread/Other/VolatileDemo.xaml

    <Page
        x:Class="XamlDemo.Thread.Other.VolatileDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:XamlDemo.Thread.Other"
        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 FontSize="14.667" LineHeight="20">
                    <Run>如果编译器认为某字段无外部修改,则为了优化会将其放入寄存器</Run>
                    <LineBreak />
                    <Run>标记为 volatile 的字段,则必然会被放进内存</Run>
                    <LineBreak />
                    <Run>编写 Windows Store Apps 后台任务类的时候,如果某个字段会被后台任务的调用者修改的话,就要将其标记为 volatile,因为这种情况下编译器会认为此字段无外部修改</Run>
                </TextBlock>
    
            </StackPanel>
        </Grid>
    </Page>


    4、演示 SynchronizationContext 的使用
    Thread/Other/SynchronizationContextDemo.xaml.cs

    /*
     * SynchronizationContext - 在指定的线程上同步数据
     *     Current - 获取当前线程的 SynchronizationContext 对象
     *     Post(SendOrPostCallback d, object state) - 同步数据到此 SynchronizationContext 所关联的线程上
     */
    
    using System;
    using Windows.System.Threading;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    
    namespace XamlDemo.Thread.Other
    {
        public sealed partial class SynchronizationContextDemo : Page
        {
            System.Threading.SynchronizationContext _syncContext;
    
            public SynchronizationContextDemo()
            {
                this.InitializeComponent();
    
                // 获取当前线程,即 UI 线程
                _syncContext = System.Threading.SynchronizationContext.Current;
    
                ThreadPoolTimer.CreatePeriodicTimer(
                   (timer) =>
                   {
                       // 在指定的线程(UI 线程)上同步数据
                       _syncContext.Post(
                           (ctx) =>
                           {
                               lblMsg.Text = DateTime.Now.ToString("mm:ss.fff");
                           },
                           null);
                   },
                   TimeSpan.FromMilliseconds(100));
            }
        }
    }


    5、演示 CoreDispatcher 的使用
    Thread/Other/CoreDispatcherDemo.xaml.cs

    /*
     * CoreDispatcher - 调度器,用于线程同步
     */
    
    using System;
    using Windows.System.Threading;
    using Windows.UI.Core;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    namespace XamlDemo.Thread.Other
    {
        public sealed partial class CoreDispatcherDemo : Page
        {
            public CoreDispatcherDemo()
            {
                this.InitializeComponent();
    
                // 获取 UI 线程的 CoreDispatcher
                CoreDispatcher dispatcher = Window.Current.Dispatcher;
    
                ThreadPoolTimer.CreatePeriodicTimer(
                   (timer) =>
                   {
                       // 通过 CoreDispatcher 同步数据
                       // var ignored = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                       var ignored = dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                           () =>
                           {
                               lblMsg.Text = DateTime.Now.ToString("mm:ss.fff");
                           });
                   },
                   TimeSpan.FromMilliseconds(100));
            }
        }
    }


    6、演示 ThreadLocal 的使用
    Thread/Other/ThreadLocalDemo.xaml.cs

    /*
     * ThreadLocal<T> - 用于保存每个线程自己的数据,T - 需要保存的数据的数据类型
     *     ThreadLocal(Func<T> valueFactory, bool trackAllValues) - 构造函数
     *         valueFactory - 指定当前线程个性化数据的初始值
     *         trackAllValues - 是否需要获取所有线程的个性化数据
     *     T Value - 当前线程的个性化数据
     *     IList<T> Values - 获取所有线程的个性化数据(trackAllValues == true 才能获取)
     *     
     * 
     * 注:ThreadStaticAttribute 与 ThreadLocal<T> 的作用差不多
     */
    
    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    
    namespace XamlDemo.Thread.Other
    {
        public sealed partial class ThreadLocalDemo : Page
        {
            System.Threading.SynchronizationContext _syncContext;
    
            public ThreadLocalDemo()
            {
                this.InitializeComponent();
    
                // 获取当前线程,即 UI 线程
                _syncContext = System.Threading.SynchronizationContext.Current;
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                ThreadLocal<string> localThread = new ThreadLocal<string>(
                    () => "ui thread webabcd", // ui 线程的个性化数据
                    false);
    
                Task.Run(() =>
                {
                    // 此任务的个性化数据
                    localThread.Value = "thread 1 webabcd";
    
                    _syncContext.Post((ctx) =>
                    {
                        lblMsg.Text += Environment.NewLine;
                        lblMsg.Text += ctx.ToString();
                    },
                    localThread.Value);
                });
    
                Task.Run(() =>
                {
                    // 此任务的个性化数据
                    localThread.Value = "thread 2 webabcd";
    
                    _syncContext.Post((ctx) =>
                    {
                        lblMsg.Text += Environment.NewLine;
                        lblMsg.Text += ctx.ToString();
                    },
                    localThread.Value);
                });
    
                lblMsg.Text += localThread.Value;
            }
        }
    }


    7、演示 ThreadStaticAttribute 的使用
    Thread/Other/ThreadStaticAttributeDemo.xaml.cs

    /*
     * ThreadStaticAttribute - 所指定的静态变量对每个线程都是唯一的
     * 
     * 
     * 注:ThreadStaticAttribute 与 ThreadLocal<T> 的作用差不多
     */
    
    using System;
    using System.Threading.Tasks;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    
    namespace XamlDemo.Thread.Other
    {
        public sealed partial class ThreadStaticAttributeDemo : Page
        {
            // 此静态变量对每个线程都是唯一的
            [ThreadStatic]
            private static int _testValue = 0;
    
            System.Threading.SynchronizationContext _syncContext;
    
            public ThreadStaticAttributeDemo()
            {
                this.InitializeComponent();
    
                // 获取当前线程,即 UI 线程
                _syncContext = System.Threading.SynchronizationContext.Current;
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                Task.Run(() =>
                {
                    _testValue = 10;
    
                    _syncContext.Post((testValue) =>
                    {
                        lblMsg.Text += Environment.NewLine;
                        // 此 Task 上的 _testValue 的值
                        lblMsg.Text += "thread 1 testValue: " + testValue.ToString();
                    },
                    _testValue);
                });
    
                Task.Run(() =>
                {
                    _testValue = 100;
    
                    _syncContext.Post((testValue) =>
                    {
                        lblMsg.Text += Environment.NewLine;
                        // 此 Task 上的 _testValue 的值
                        lblMsg.Text += "thread 2 testValue: " + testValue.ToString();
                    },
                    _testValue);
                });
    
                // ui 线程上的 _testValue 的值
                lblMsg.Text = "ui thread testValue: " + _testValue.ToString();
            }
        }
    }



    OK
    [源码下载]

  • 相关阅读:
    P4009 汽车加油行驶问题
    P2761 软件补丁问题
    P1251 餐巾计划问题
    P2766 最长不下降子序列问题
    P4011 孤岛营救问题
    P2765 魔术球问题
    P2770 航空路线问题
    P2762 太空飞行计划问题
    P2764 最小路径覆盖问题
    P3355 骑士共存问题
  • 原文地址:https://www.cnblogs.com/webabcd/p/3237432.html
Copyright © 2011-2022 走看看