Sfoglia il codice sorgente

增加同时只能执行一个任务的TaskScheduler.

tanghai 15 anni fa
parent
commit
7e8c52f8e3

+ 6 - 0
CSharp/CSharp.sln

@@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 11.00
 # Visual Studio 2010
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Editor", "Editor\Editor.csproj", "{B29100C8-6E7F-4C7D-91AB-0153D0D28663}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thread", "Thread\Thread.csproj", "{01AE803B-71F3-4DD6-BEAA-6BA7C2D13E23}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -13,6 +15,10 @@ Global
 		{B29100C8-6E7F-4C7D-91AB-0153D0D28663}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{B29100C8-6E7F-4C7D-91AB-0153D0D28663}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{B29100C8-6E7F-4C7D-91AB-0153D0D28663}.Release|Any CPU.Build.0 = Release|Any CPU
+		{01AE803B-71F3-4DD6-BEAA-6BA7C2D13E23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{01AE803B-71F3-4DD6-BEAA-6BA7C2D13E23}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{01AE803B-71F3-4DD6-BEAA-6BA7C2D13E23}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{01AE803B-71F3-4DD6-BEAA-6BA7C2D13E23}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 2 - 2
CSharp/Editor/App.xaml

@@ -1,7 +1,7 @@
-<Application x:Class="Editor.App"
+<Application x:Class="Egametang.App"
 		xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 		xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-		xmlns:vm="clr-namespace:Editor.ViewModel"
+		xmlns:vm="clr-namespace:Egametang"
 		xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 		xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 		StartupUri="MainWindow.xaml"

+ 1 - 1
CSharp/Editor/App.xaml.cs

@@ -2,7 +2,7 @@
 using GalaSoft.MvvmLight.Threading;
 using System.ComponentModel;
 
-namespace Editor
+namespace Egametang
 {
 	/// <summary>
 	/// Interaction logic for App.xaml

+ 9 - 22
CSharp/Editor/Editor.csproj

@@ -95,30 +95,17 @@
     </Page>
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="Properties\AssemblyInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="Properties\Resources.Designer.cs">
-      <AutoGen>True</AutoGen>
-      <DesignTime>True</DesignTime>
-      <DependentUpon>Resources.resx</DependentUpon>
-    </Compile>
-    <Compile Include="Properties\Settings.Designer.cs">
-      <AutoGen>True</AutoGen>
-      <DependentUpon>Settings.settings</DependentUpon>
-      <DesignTimeSharedInput>True</DesignTimeSharedInput>
-    </Compile>
-    <EmbeddedResource Include="Properties\Resources.resx">
-      <Generator>ResXFileCodeGenerator</Generator>
-      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
-    </EmbeddedResource>
-    <None Include="Properties\Settings.settings">
-      <Generator>SettingsSingleFileGenerator</Generator>
-      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
-    </None>
     <AppDesigner Include="Properties\" />
   </ItemGroup>
-  <ItemGroup />
+  <ItemGroup>
+    <Folder Include="Properties\" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Thread\Thread.csproj">
+      <Project>{01AE803B-71F3-4DD6-BEAA-6BA7C2D13E23}</Project>
+      <Name>Thread</Name>
+    </ProjectReference>
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

+ 2 - 2
CSharp/Editor/MainWindow.xaml

@@ -1,9 +1,9 @@
-<Window x:Class="Editor.MainWindow"
+<Window x:Class="Egametang.MainWindow"
 		xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 		xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 		xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 		xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-		xmlns:v="clr-namespace:Editor.View"
+		xmlns:v="clr-namespace:Egametang"
 		mc:Ignorable="d" Height="600" Width="800" Title="MVVM Light Application"
 		DataContext="{Binding Main, Source={StaticResource Locator}}">
 	<Grid x:Name="LayoutRoot">

+ 1 - 2
CSharp/Editor/MainWindow.xaml.cs

@@ -1,7 +1,6 @@
 using System.Windows;
-using Editor.ViewModel;
 
-namespace Editor
+namespace Egametang
 {
 	/// <summary>
 	/// Interaction logic for MainWindow.xaml

+ 1 - 1
CSharp/Editor/Model/DataService.cs

@@ -1,6 +1,6 @@
 using System;
 
-namespace Editor.Model
+namespace Egametang
 {
 	public class DataService : IDataService
 	{

+ 1 - 1
CSharp/Editor/Model/IDataService.cs

@@ -3,7 +3,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 
-namespace Editor.Model
+namespace Egametang
 {
 	public interface IDataService
 	{

+ 1 - 1
CSharp/Editor/View/MainView.xaml

@@ -1,4 +1,4 @@
-<UserControl x:Class="Editor.View.MainView"
+<UserControl x:Class="Egametang.MainView"
 		xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 		xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 		xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 

+ 1 - 1
CSharp/Editor/View/MainView.xaml.cs

@@ -12,7 +12,7 @@ using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
 using System.Windows.Shapes;
 
-namespace Editor.View
+namespace Egametang
 {
 	/// <summary>
 	/// MainView.xaml 的交互逻辑

+ 16 - 16
CSharp/Editor/ViewModel/MainViewModel.cs

@@ -1,16 +1,18 @@
 using System;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Schedulers;
 using System.Windows.Threading;
-using Editor.Model;
 using GalaSoft.MvvmLight;
 using GalaSoft.MvvmLight.Command;
 using GalaSoft.MvvmLight.Threading;
 
-namespace Editor.ViewModel
+namespace Egametang
 {
 	public class MainViewModel : ViewModelBase
 	{
 		private readonly IDataService dataService;
 		private string loginResult = "";
+		private OrderedTaskScheduler orderedTaskScheduler = new OrderedTaskScheduler();
 
 		public MainViewModel(IDataService dataService)
 		{
@@ -43,21 +45,19 @@ namespace Editor.ViewModel
 
 		private void AsyncLogin()
 		{
-			Action showLoginResult = () =>
-				{
-					LoginResult = "Login OK!";
-				};
-			AsyncCallback callback = (obj) =>
-				{
-					DispatcherHelper.UIDispatcher.BeginInvoke(
-						DispatcherPriority.Normal, showLoginResult);
-				};
+			var task = new Task(() =>
+			{
 
-			Action asynLogin = () =>
-				{
-					
-				};
-			asynLogin.BeginInvoke(callback, null);
+			});
+			task.ContinueWith(_ =>
+			{
+				DispatcherHelper.UIDispatcher.BeginInvoke(DispatcherPriority.Normal,
+					new Action(() =>
+					{
+						LoginResult = "Login OK!";
+					}));
+			}, orderedTaskScheduler);
+			task.Start();
 		}
 
 		public override void Cleanup()

+ 1 - 2
CSharp/Editor/ViewModel/ViewModelLocator.cs

@@ -1,9 +1,8 @@
 using GalaSoft.MvvmLight;
 using GalaSoft.MvvmLight.Ioc;
 using Microsoft.Practices.ServiceLocation;
-using Editor.Model;
 
-namespace Editor.ViewModel
+namespace Egametang
 {
 	public class ViewModelLocator
 	{

+ 172 - 0
CSharp/Thread/LimitedConcurrencyLevelTaskScheduler.cs

@@ -0,0 +1,172 @@
+//--------------------------------------------------------------------------
+// 
+//  Copyright (c) Microsoft Corporation.  All rights reserved. 
+// 
+//  File: LimitedConcurrencyTaskScheduler.cs
+//
+//--------------------------------------------------------------------------
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace System.Threading.Tasks.Schedulers
+{
+	/// <summary>
+	/// Provides a task scheduler that ensures a maximum concurrency level while
+	/// running on top of the ThreadPool.
+	/// </summary>
+	public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
+	{
+		/// <summary>Whether the current thread is processing work items.</summary>
+		[ThreadStatic]
+		private static bool currentThreadIsProcessingItems;
+		/// <summary>The list of tasks to be executed.</summary>
+		private readonly LinkedList<Task> tasks = new LinkedList<Task>(); // protected by lock(tasks)
+		/// <summary>The maximum concurrency level allowed by this scheduler.</summary>
+		private readonly int maxDegreeOfParallelism;
+		/// <summary>Whether the scheduler is currently processing work items.</summary>
+		private int delegatesQueuedOrRunning = 0; // protected by lock(tasks)
+
+		/// <summary>
+		/// Initializes an instance of the LimitedConcurrencyLevelTaskScheduler class with the
+		/// specified degree of parallelism.
+		/// </summary>
+		/// <param name="maxDegreeOfParallelism">The maximum degree of parallelism provided by this scheduler.</param>
+		public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
+		{
+			if (maxDegreeOfParallelism < 1)
+			{
+				throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");
+			}
+			this.maxDegreeOfParallelism = maxDegreeOfParallelism;
+		}
+
+		/// <summary>Queues a task to the scheduler.</summary>
+		/// <param name="task">The task to be queued.</param>
+		protected sealed override void QueueTask(Task task)
+		{
+			// Add the task to the list of tasks to be processed.  If there aren't enough
+			// delegates currently queued or running to process tasks, schedule another.
+			lock (tasks)
+			{
+				tasks.AddLast(task);
+				if (delegatesQueuedOrRunning < maxDegreeOfParallelism)
+				{
+					++delegatesQueuedOrRunning;
+					NotifyThreadPoolOfPendingWork();
+				}
+			}
+		}
+
+		/// <summary>
+		/// Informs the ThreadPool that there's work to be executed for this scheduler.
+		/// </summary>
+		private void NotifyThreadPoolOfPendingWork()
+		{
+			ThreadPool.UnsafeQueueUserWorkItem(_ =>
+			{
+				// Note that the current thread is now processing work items.
+				// This is necessary to enable inlining of tasks into this thread.
+				currentThreadIsProcessingItems = true;
+				try
+				{
+					// Process all available items in the queue.
+					while (true)
+					{
+						Task item;
+						lock (tasks)
+						{
+							// When there are no more items to be processed,
+							// note that we're done processing, and get out.
+							if (tasks.Count == 0)
+							{
+								--delegatesQueuedOrRunning;
+								break;
+							}
+
+							// Get the next item from the queue
+							item = tasks.First.Value;
+							tasks.RemoveFirst();
+						}
+
+						// Execute the task we pulled out of the queue
+						base.TryExecuteTask(item);
+					}
+				}
+				// We're done processing items on the current thread
+				finally 
+				{ 
+					currentThreadIsProcessingItems = false; 
+				}
+			}, null);
+		}
+
+		/// <summary>Attempts to execute the specified task on the current thread.</summary>
+		/// <param name="task">The task to be executed.</param>
+		/// <param name="taskWasPreviouslyQueued"></param>
+		/// <returns>Whether the task could be executed on the current thread.</returns>
+		protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
+		{
+			// If this thread isn't already processing a task, we don't support inlining
+			if (!currentThreadIsProcessingItems)
+			{
+				return false;
+			}
+
+			// If the task was previously queued, remove it from the queue
+			if (taskWasPreviouslyQueued)
+			{
+				TryDequeue(task);
+			}
+
+			// Try to run the task.
+			return base.TryExecuteTask(task);
+		}
+
+		/// <summary>Attempts to remove a previously scheduled task from the scheduler.</summary>
+		/// <param name="task">The task to be removed.</param>
+		/// <returns>Whether the task could be found and removed.</returns>
+		protected sealed override bool TryDequeue(Task task)
+		{
+			lock (tasks)
+			{
+				return tasks.Remove(task);
+			}
+		}
+
+		/// <summary>Gets the maximum concurrency level supported by this scheduler.</summary>
+		public sealed override int MaximumConcurrencyLevel 
+		{ 
+			get 
+			{ 
+				return maxDegreeOfParallelism; 
+			} 
+		}
+
+		/// <summary>Gets an enumerable of the tasks currently scheduled on this scheduler.</summary>
+		/// <returns>An enumerable of the tasks currently scheduled.</returns>
+		protected sealed override IEnumerable<Task> GetScheduledTasks()
+		{
+			bool lockTaken = false;
+			try
+			{
+				Monitor.TryEnter(tasks, ref lockTaken);
+				if (lockTaken)
+				{
+					return tasks.ToArray();
+				}
+				else
+				{
+					throw new NotSupportedException();
+				}
+			}
+			finally
+			{
+				if (lockTaken)
+				{
+					Monitor.Exit(tasks);
+				}
+			}
+		}
+	}
+}

+ 20 - 0
CSharp/Thread/OrderedTaskScheduler.cs

@@ -0,0 +1,20 @@
+//--------------------------------------------------------------------------
+// 
+//  Copyright (c) Microsoft Corporation.  All rights reserved. 
+// 
+//  File: OrderedTaskScheduler.cs
+//
+//--------------------------------------------------------------------------
+
+namespace System.Threading.Tasks.Schedulers
+{
+    /// <summary>
+    /// Provides a task scheduler that ensures only one task is executing at a time, and that tasks
+    /// execute in the order that they were queued.
+    /// </summary>
+    public sealed class OrderedTaskScheduler : LimitedConcurrencyLevelTaskScheduler
+    {
+        /// <summary>Initializes an instance of the OrderedTaskScheduler class.</summary>
+        public OrderedTaskScheduler() : base(1) { }
+    }
+}

+ 55 - 0
CSharp/Thread/Thread.csproj

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{01AE803B-71F3-4DD6-BEAA-6BA7C2D13E23}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Thread</RootNamespace>
+    <AssemblyName>Thread</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="LimitedConcurrencyLevelTaskScheduler.cs" />
+    <Compile Include="OrderedTaskScheduler.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>