You've already forked linux-packaging-mono
Imported Upstream version 3.8.0
Former-commit-id: 6a76a29bd07d86e57c6c8da45c65ed5447d38a61
This commit is contained in:
@@ -1,139 +0,0 @@
|
||||
// Scheduler.cs
|
||||
//
|
||||
// Copyright (c) 2008 Jérémie "Garuma" Laval
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
//
|
||||
|
||||
#if NET_4_0
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Mono.Threading.Tasks
|
||||
{
|
||||
public class FixedTaskScheduler: TaskScheduler, IMonoTaskScheduler
|
||||
{
|
||||
readonly IProducerConsumerCollection<Task> workQueue;
|
||||
readonly ThreadWorker[] workers;
|
||||
readonly ManualResetEvent pulseHandle = new ManualResetEvent (false);
|
||||
|
||||
public FixedTaskScheduler ()
|
||||
: this (Environment.ProcessorCount, ThreadPriority.Normal)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public FixedTaskScheduler (int maxWorker, ThreadPriority priority)
|
||||
{
|
||||
workQueue = new ConcurrentQueue<Task> ();
|
||||
workers = new ThreadWorker [maxWorker];
|
||||
|
||||
for (int i = 0; i < maxWorker; i++) {
|
||||
workers [i] = new ThreadWorker (workers, i, workQueue, new CyclicDeque<Task> (), priority, pulseHandle);
|
||||
workers [i].Pulse ();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void QueueTask (Task t)
|
||||
{
|
||||
// Add to the shared work pool
|
||||
workQueue.TryAdd (t);
|
||||
// Wake up some worker if they were asleep
|
||||
PulseAll ();
|
||||
}
|
||||
|
||||
public void MonoParticipateUntil (Task task)
|
||||
{
|
||||
if (task.IsCompleted)
|
||||
return;
|
||||
|
||||
ManualResetEventSlim evt = new ManualResetEventSlim (false);
|
||||
task.ContinueWith (_ => evt.Set (), TaskContinuationOptions.ExecuteSynchronously);
|
||||
if (evt.IsSet || task.IsCompleted)
|
||||
return;
|
||||
|
||||
ParticipateUntilInternal (task, evt, -1);
|
||||
}
|
||||
|
||||
public bool MonoParticipateUntil (Task task, ManualResetEventSlim evt, int millisecondsTimeout)
|
||||
{
|
||||
if (task.IsCompleted)
|
||||
return false;
|
||||
|
||||
bool isFromPredicate = true;
|
||||
task.ContinueWith (_ => { isFromPredicate = false; evt.Set (); }, TaskContinuationOptions.ExecuteSynchronously);
|
||||
|
||||
ParticipateUntilInternal (task, evt, millisecondsTimeout);
|
||||
|
||||
if (task.IsCompleted)
|
||||
return false;
|
||||
|
||||
return isFromPredicate;
|
||||
}
|
||||
|
||||
public void ParticipateUntilInternal (Task self, ManualResetEventSlim evt, int millisecondsTimeout)
|
||||
{
|
||||
ThreadWorker.ParticipativeWorkerMethod (self, evt, millisecondsTimeout, workQueue, workers, pulseHandle, (a, b) => true);
|
||||
}
|
||||
|
||||
static bool TaskCompletedPredicate (Task self)
|
||||
{
|
||||
return self.IsCompleted;
|
||||
}
|
||||
|
||||
public void PulseAll ()
|
||||
{
|
||||
pulseHandle.Set ();
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
foreach (ThreadWorker w in workers)
|
||||
w.Dispose ();
|
||||
}
|
||||
|
||||
#region Scheduler dummy stubs
|
||||
protected override System.Collections.Generic.IEnumerable<Task> GetScheduledTasks ()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
protected override bool TryDequeue (Task task)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQueued)
|
||||
{
|
||||
task.Execute (null);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int MaximumConcurrencyLevel {
|
||||
get {
|
||||
return base.MaximumConcurrencyLevel;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,54 +0,0 @@
|
||||
//
|
||||
// MonoTaskExtensions.cs
|
||||
//
|
||||
// Author:
|
||||
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2011 Jérémie "Garuma" Laval
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#if NET_4_0
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Mono.Threading.Tasks
|
||||
{
|
||||
public static class MonoTaskExtensions
|
||||
{
|
||||
readonly static Action<Task, Action<Task>> internalExecute = null;
|
||||
|
||||
static MonoTaskExtensions ()
|
||||
{
|
||||
// Initialize internal execute
|
||||
var method = typeof(Task).GetMethod ("Execute", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
internalExecute = (Action<Task, Action<Task>>)Delegate.CreateDelegate (typeof(Action<Task, Action<Task>>), method);
|
||||
}
|
||||
|
||||
// Allow external worker to call into the otherwise internal corresponding method of Task
|
||||
public static void Execute (this Task task, Action<Task> childWorkAdder)
|
||||
{
|
||||
internalExecute (task, childWorkAdder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
//
|
||||
// MonoTaskScheduler.cs
|
||||
//
|
||||
// Author:
|
||||
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2011 Jérémie "Garuma" Laval
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#if NET_4_0
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Mono.Threading.Tasks
|
||||
{
|
||||
public interface IMonoTaskScheduler
|
||||
{
|
||||
void MonoParticipateUntil (Task task);
|
||||
bool MonoParticipateUntil (Task task, ManualResetEventSlim predicateEvt, int millisecondsTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,421 +0,0 @@
|
||||
// ThreadWorker.cs
|
||||
//
|
||||
// Copyright (c) 2008 Jérémie "Garuma" Laval
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
//
|
||||
|
||||
#if NET_4_0
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading.Tasks;
|
||||
using Watch = System.Diagnostics.Stopwatch;
|
||||
|
||||
namespace Mono.Threading.Tasks
|
||||
{
|
||||
public class ThreadWorker : IDisposable
|
||||
{
|
||||
Thread workerThread;
|
||||
|
||||
/* This field is used when a TheadWorker have to call Task.Wait
|
||||
* which bring him back here with the static WorkerMethod although
|
||||
* it's more optimized for him to continue calling its own WorkerMethod
|
||||
*/
|
||||
[ThreadStatic]
|
||||
static ThreadWorker autoReference;
|
||||
|
||||
readonly IConcurrentDeque<Task> dDeque;
|
||||
readonly ThreadWorker[] others;
|
||||
readonly ManualResetEvent waitHandle;
|
||||
readonly IProducerConsumerCollection<Task> sharedWorkQueue;
|
||||
readonly ThreadPriority threadPriority;
|
||||
|
||||
// Flag to tell if workerThread is running
|
||||
int started = 0;
|
||||
|
||||
readonly int workerLength;
|
||||
readonly int workerPosition;
|
||||
const int maxRetry = 3;
|
||||
|
||||
const int sleepThreshold = 100;
|
||||
int deepSleepTime = 8;
|
||||
readonly Action<Task> adder;
|
||||
|
||||
Task currentTask;
|
||||
|
||||
public ThreadWorker (ThreadWorker[] others,
|
||||
int workerPosition,
|
||||
IProducerConsumerCollection<Task> sharedWorkQueue,
|
||||
IConcurrentDeque<Task> dDeque,
|
||||
ThreadPriority priority,
|
||||
ManualResetEvent handle)
|
||||
{
|
||||
this.others = others;
|
||||
this.dDeque = dDeque;
|
||||
this.sharedWorkQueue = sharedWorkQueue;
|
||||
this.workerLength = others.Length;
|
||||
this.workerPosition = workerPosition;
|
||||
this.waitHandle = handle;
|
||||
this.threadPriority = priority;
|
||||
this.adder = new Action<Task> (ChildWorkAdder);
|
||||
|
||||
InitializeUnderlyingThread ();
|
||||
}
|
||||
|
||||
protected virtual void InitializeUnderlyingThread ()
|
||||
{
|
||||
this.workerThread = new Thread (WorkerMethodWrapper);
|
||||
|
||||
this.workerThread.IsBackground = true;
|
||||
this.workerThread.Priority = threadPriority;
|
||||
this.workerThread.Name = "ParallelFxThreadWorker";
|
||||
}
|
||||
|
||||
public virtual void Dispose ()
|
||||
{
|
||||
Stop ();
|
||||
if (workerThread.ThreadState != ThreadState.Stopped)
|
||||
workerThread.Abort ();
|
||||
}
|
||||
|
||||
public virtual void Pulse ()
|
||||
{
|
||||
if (started == 1)
|
||||
return;
|
||||
|
||||
// If the thread was stopped then set it in use and restart it
|
||||
int result = Interlocked.Exchange (ref started, 1);
|
||||
if (result != 0)
|
||||
return;
|
||||
|
||||
if (this.workerThread.ThreadState != ThreadState.Unstarted) {
|
||||
InitializeUnderlyingThread ();
|
||||
}
|
||||
|
||||
workerThread.Start ();
|
||||
}
|
||||
|
||||
public virtual void Stop ()
|
||||
{
|
||||
// Set the flag to stop so that the while in the thread will stop
|
||||
// doing its infinite loop.
|
||||
started = 0;
|
||||
}
|
||||
|
||||
// This is the actual method called in the Thread
|
||||
protected virtual void WorkerMethodWrapper ()
|
||||
{
|
||||
int sleepTime = 0;
|
||||
autoReference = this;
|
||||
bool wasWokenUp = false;
|
||||
|
||||
// Main loop
|
||||
while (started == 1) {
|
||||
bool result = false;
|
||||
|
||||
result = WorkerMethod ();
|
||||
if (!result && wasWokenUp)
|
||||
waitHandle.Reset ();
|
||||
wasWokenUp = false;
|
||||
|
||||
Thread.Yield ();
|
||||
|
||||
if (result) {
|
||||
deepSleepTime = 8;
|
||||
sleepTime = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we are spinning too much, have a deeper sleep
|
||||
if (++sleepTime > sleepThreshold && sharedWorkQueue.Count == 0) {
|
||||
wasWokenUp = waitHandle.WaitOne ((deepSleepTime = deepSleepTime >= 0x4000 ? 0x4000 : deepSleepTime << 1));
|
||||
}
|
||||
}
|
||||
|
||||
started = 0;
|
||||
}
|
||||
|
||||
// Main method, used to do all the logic of retrieving, processing and stealing work.
|
||||
protected virtual bool WorkerMethod ()
|
||||
{
|
||||
bool result = false;
|
||||
bool hasStolenFromOther;
|
||||
|
||||
do {
|
||||
hasStolenFromOther = false;
|
||||
|
||||
Task value;
|
||||
|
||||
// We fill up our work deque concurrently with other ThreadWorker
|
||||
while (sharedWorkQueue.Count > 0) {
|
||||
waitHandle.Set ();
|
||||
|
||||
while (sharedWorkQueue.TryTake (out value)) {
|
||||
dDeque.PushBottom (value);
|
||||
}
|
||||
|
||||
// Now we process our work
|
||||
while (dDeque.PopBottom (out value) == PopResult.Succeed) {
|
||||
waitHandle.Set ();
|
||||
ExecuteTask (value, ref result);
|
||||
}
|
||||
}
|
||||
|
||||
// When we have finished, steal from other worker
|
||||
ThreadWorker other;
|
||||
|
||||
// Repeat the operation a little so that we can let other things process.
|
||||
for (int j = 0; j < maxRetry; ++j) {
|
||||
int len = workerLength + workerPosition;
|
||||
// Start stealing with the ThreadWorker at our right to minimize contention
|
||||
for (int it = workerPosition + 1; it < len; ++it) {
|
||||
int i = it % workerLength;
|
||||
if ((other = others [i]) == null || other == this)
|
||||
continue;
|
||||
|
||||
// Maybe make this steal more than one item at a time, see TODO.
|
||||
while (other.dDeque.PopTop (out value) == PopResult.Succeed) {
|
||||
if (!hasStolenFromOther)
|
||||
waitHandle.Set ();
|
||||
|
||||
hasStolenFromOther = true;
|
||||
ExecuteTask (value, ref result);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (sharedWorkQueue.Count > 0 || hasStolenFromOther);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ExecuteTask (Task value, ref bool result)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
var saveCurrent = currentTask;
|
||||
currentTask = value;
|
||||
value.Execute (adder);
|
||||
result = true;
|
||||
currentTask = saveCurrent;
|
||||
}
|
||||
|
||||
// Almost same as above but with an added predicate and treating one item at a time.
|
||||
// It's used by Scheduler Participate(...) method for special waiting case like
|
||||
// Task.WaitAll(someTasks) or Task.WaitAny(someTasks)
|
||||
// Predicate should be really fast and not blocking as it is called a good deal of time
|
||||
// Also, the method skip tasks that are LongRunning to avoid blocking (Task are not LongRunning by default)
|
||||
public static void ParticipativeWorkerMethod (Task self,
|
||||
ManualResetEventSlim predicateEvt,
|
||||
int millisecondsTimeout,
|
||||
IProducerConsumerCollection<Task> sharedWorkQueue,
|
||||
ThreadWorker[] others,
|
||||
ManualResetEvent evt,
|
||||
Func<Task, Task, bool> checkTaskFitness)
|
||||
{
|
||||
const int stage1 = 5, stage2 = 0;
|
||||
int tries = 50;
|
||||
WaitHandle[] handles = null;
|
||||
Watch watch = Watch.StartNew ();
|
||||
if (millisecondsTimeout == -1)
|
||||
millisecondsTimeout = int.MaxValue;
|
||||
bool aggressive = false;
|
||||
bool hasAutoReference = autoReference != null;
|
||||
Action<Task> adder = null;
|
||||
|
||||
while (!predicateEvt.IsSet && watch.ElapsedMilliseconds < millisecondsTimeout && !self.IsCompleted) {
|
||||
// We try to execute the self task as it may be the simplest way to unlock
|
||||
// the situation
|
||||
if (self.Status == TaskStatus.WaitingToRun) {
|
||||
self.Execute (hasAutoReference ? autoReference.adder : (Action<Task>)null);
|
||||
if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout)
|
||||
return;
|
||||
}
|
||||
|
||||
Task value;
|
||||
|
||||
// If we are in fact a normal ThreadWorker, use our own deque
|
||||
if (hasAutoReference) {
|
||||
var enumerable = autoReference.dDeque.GetEnumerable ();
|
||||
if (adder == null)
|
||||
adder = hasAutoReference ? autoReference.adder : (Action<Task>)null;
|
||||
|
||||
if (enumerable != null) {
|
||||
foreach (var t in enumerable) {
|
||||
if (t == null)
|
||||
continue;
|
||||
|
||||
if (checkTaskFitness (self, t))
|
||||
t.Execute (adder);
|
||||
|
||||
if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int count = sharedWorkQueue.Count;
|
||||
|
||||
// Dequeue only one item as we have restriction
|
||||
while (--count >= 0 && sharedWorkQueue.TryTake (out value) && value != null) {
|
||||
evt.Set ();
|
||||
if (checkTaskFitness (self, value) || aggressive)
|
||||
value.Execute (null);
|
||||
else {
|
||||
if (autoReference == null)
|
||||
sharedWorkQueue.TryAdd (value);
|
||||
else
|
||||
autoReference.dDeque.PushBottom (value);
|
||||
evt.Set ();
|
||||
}
|
||||
|
||||
if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout)
|
||||
return;
|
||||
}
|
||||
|
||||
// First check to see if we comply to predicate
|
||||
if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout)
|
||||
return;
|
||||
|
||||
// Try to complete other work by stealing since our desired tasks may be in other worker
|
||||
ThreadWorker other;
|
||||
for (int i = 0; i < others.Length; i++) {
|
||||
if ((other = others [i]) == autoReference || other == null)
|
||||
continue;
|
||||
|
||||
if (other.dDeque.PopTop (out value) == PopResult.Succeed && value != null) {
|
||||
evt.Set ();
|
||||
if (checkTaskFitness (self, value) || aggressive)
|
||||
value.Execute (null);
|
||||
else {
|
||||
if (autoReference == null)
|
||||
sharedWorkQueue.TryAdd (value);
|
||||
else
|
||||
autoReference.dDeque.PushBottom (value);
|
||||
evt.Set ();
|
||||
}
|
||||
}
|
||||
|
||||
if (predicateEvt.IsSet || watch.ElapsedMilliseconds > millisecondsTimeout)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Waiting is split in 4 phases
|
||||
* - until stage 1 we simply yield the thread to let others add data
|
||||
* - between stage 1 and stage2 we use ManualResetEventSlim light waiting mechanism
|
||||
* - after stage2 we fall back to the heavier WaitHandle waiting mechanism
|
||||
* - if really the situation isn't evolving after a couple of sleep, we disable
|
||||
* task fitness check altogether
|
||||
*/
|
||||
if (--tries > stage1)
|
||||
Thread.Yield ();
|
||||
else if (tries >= stage2)
|
||||
predicateEvt.Wait (ComputeTimeout (5, millisecondsTimeout, watch));
|
||||
else {
|
||||
if (tries == stage2 - 1)
|
||||
handles = new [] { predicateEvt.WaitHandle, evt };
|
||||
System.Threading.WaitHandle.WaitAny (handles, ComputeTimeout (1000, millisecondsTimeout, watch));
|
||||
if (tries == stage2 - 10)
|
||||
aggressive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ThreadWorker AutoReference {
|
||||
get {
|
||||
return autoReference;
|
||||
}
|
||||
set {
|
||||
autoReference = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected IConcurrentDeque<Task> Deque {
|
||||
get {
|
||||
return dDeque;
|
||||
}
|
||||
}
|
||||
|
||||
protected ThreadWorker[] Others {
|
||||
get {
|
||||
return others;
|
||||
}
|
||||
}
|
||||
|
||||
protected ManualResetEvent WaitHandle {
|
||||
get {
|
||||
return waitHandle;
|
||||
}
|
||||
}
|
||||
|
||||
protected ThreadPriority Priority {
|
||||
get {
|
||||
return threadPriority;
|
||||
}
|
||||
}
|
||||
|
||||
protected int WorkerPosition {
|
||||
get {
|
||||
return workerPosition;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ChildWorkAdder (Task t)
|
||||
{
|
||||
dDeque.PushBottom (t);
|
||||
waitHandle.Set ();
|
||||
}
|
||||
|
||||
static int ComputeTimeout (int proposed, int timeout, Watch watch)
|
||||
{
|
||||
return timeout == int.MaxValue ? proposed : System.Math.Min (proposed, System.Math.Max (0, (int)(timeout - watch.ElapsedMilliseconds)));
|
||||
}
|
||||
|
||||
public bool Finished {
|
||||
get {
|
||||
return started == 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int Id {
|
||||
get {
|
||||
return workerThread.ManagedThreadId;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool Equals (ThreadWorker other)
|
||||
{
|
||||
return (other == null) ? false : object.ReferenceEquals (this.dDeque, other.dDeque);
|
||||
}
|
||||
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
ThreadWorker temp = obj as ThreadWorker;
|
||||
return temp == null ? false : Equals (temp);
|
||||
}
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return workerThread.ManagedThreadId.GetHashCode ();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user