// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. #if WINDOWS using System.Reactive.Concurrency; using System.Reactive.Disposables; using Windows.System.Threading; namespace System.Reactive.Concurrency { /// /// Represents an object that schedules units of work on the Windows Runtime thread pool. /// /// Singleton instance of this type exposed through this static property. [CLSCompliant(false)] public sealed class ThreadPoolScheduler : LocalScheduler, ISchedulerPeriodic { private readonly WorkItemPriority _priority; private readonly WorkItemOptions _options; private static Lazy s_default = new Lazy(() => new ThreadPoolScheduler()); /// /// Constructs a ThreadPoolScheduler that schedules units of work on the Windows ThreadPool. /// public ThreadPoolScheduler() { } /// /// Constructs a ThreadPoolScheduler that schedules units of work on the Windows ThreadPool with the given priority. /// /// Priority for scheduled units of work. public ThreadPoolScheduler(WorkItemPriority priority) { _priority = priority; _options = WorkItemOptions.None; } /// /// Constructs a ThreadPoolScheduler that schedules units of work on the Windows ThreadPool with the given priority. /// /// Priority for scheduled units of work. /// Options that configure how work is scheduled. public ThreadPoolScheduler(WorkItemPriority priority, WorkItemOptions options) { _priority = priority; _options = options; } /// /// Gets the singleton instance of the Windows Runtime thread pool scheduler. /// public static ThreadPoolScheduler Default { get { return s_default.Value; } } /// /// Gets the priority at which work is scheduled. /// public WorkItemPriority Priority { get { return _priority; } } /// /// Gets the options that configure how work is scheduled. /// public WorkItemOptions Options { get { return _options; } } /// /// Schedules an action to be executed. /// /// The type of the state passed to the scheduled action. /// State passed to the action to be executed. /// Action to be executed. /// The disposable object used to cancel the scheduled action (best effort). /// is null. public override IDisposable Schedule(TState state, Func action) { if (action == null) throw new ArgumentNullException("action"); var d = new SingleAssignmentDisposable(); var res = global::Windows.System.Threading.ThreadPool.RunAsync(iaa => { if (!d.IsDisposed) d.Disposable = action(this, state); }, _priority, _options); return new CompositeDisposable( d, Disposable.Create(res.Cancel) ); } /// /// Schedules an action to be executed after dueTime, using a Windows.System.Threading.ThreadPoolTimer object. /// /// The type of the state passed to the scheduled action. /// State passed to the action to be executed. /// Action to be executed. /// Relative time after which to execute the action. /// The disposable object used to cancel the scheduled action (best effort). /// is null. public override IDisposable Schedule(TState state, TimeSpan dueTime, Func action) { if (action == null) throw new ArgumentNullException("action"); var dt = Scheduler.Normalize(dueTime); if (dt.Ticks == 0) return Schedule(state, action); var d = new SingleAssignmentDisposable(); var res = global::Windows.System.Threading.ThreadPoolTimer.CreateTimer( tpt => { if (!d.IsDisposed) d.Disposable = action(this, state); }, dt ); return new CompositeDisposable( d, Disposable.Create(res.Cancel) ); } /// /// Schedules a periodic piece of work, using a Windows.System.Threading.ThreadPoolTimer object. /// /// The type of the state passed to the scheduled action. /// Initial state passed to the action upon the first iteration. /// Period for running the work periodically. /// Action to be executed, potentially updating the state. /// The disposable object used to cancel the scheduled recurring action (best effort). /// is null. /// is less than one millisecond. public IDisposable SchedulePeriodic(TState state, TimeSpan period, Func action) { // // The WinRT thread pool is based on the Win32 thread pool and cannot handle // sub-1ms resolution. When passing a lower period, we get single-shot // timer behavior instead. See MSDN documentation for CreatePeriodicTimer // for more information. // if (period < TimeSpan.FromMilliseconds(1)) throw new ArgumentOutOfRangeException("period", Strings_PlatformServices.WINRT_NO_SUB1MS_TIMERS); if (action == null) throw new ArgumentNullException("action"); var state1 = state; var gate = new AsyncLock(); var res = global::Windows.System.Threading.ThreadPoolTimer.CreatePeriodicTimer( tpt => { gate.Wait(() => { state1 = action(state1); }); }, period ); return Disposable.Create(() => { res.Cancel(); gate.Dispose(); action = Stubs.I; }); } } } #endif