/// <summary> /// add a waiting computer. If there is an unclaimed process waiting, the /// process will be assigned to the computer and the computer's Task will be /// unblocked. Returns true if the waiter has been matched (by this call or /// another asynchronous event in the meantime). Returns false if the computer /// still needs to be matched. /// </summary> /// <param name="waiter">holder for the waiting computer</param> /// <returns></returns> public bool AddWaiter(ProcessWaiter waiter) { // process will exit the lock holding the value of the newly-claimed process, if // any. process may be non-null exiting the lock even if there was no // unclaimed process; the claimed flag below disambiguates Process process = null; // claimed will exit the lock set to true if and only if there was an unclaimed // waiter, in which case waiter will be set to the value of the waiter bool claimed = false; // lock ordering discipline is Queue first, then waiter, then process lock (this) { if (!active) { // the queue has been shut down so don't accept another waiter lock (waiter) { if (waiter.Unclaimed) { waiter.Claim(); // this will make us Dispatch the waiter with a null process below // which is correct since the queue has been shut down, and will cause // the waiting computer's commandloop to exit if it hasn't already claimed = true; } } } // even if there are processes, they may have been claimed by other computers // already, so use a loop here while (active && processQueue.Count > 0 && !claimed) { // get the next available process; don't dequeue it yet because // we have to wait until we acquire the locks below to figure out // if it's going to be matched to anything process = processQueue.Peek(); // lock ordering discipline is Queue first, then waiter, then process lock (waiter) { if (waiter.Unclaimed) { // lock ordering discipline is Queue first, then waiter, then process lock (process) { // another queue might have turned up and claimed the Process // while we were dithering; matching a process to a computer // must be done while both are locked if (process.Unclaimed) { // remove the process from the queue and match it to the computer processQueue.Dequeue(); var computer = waiter.Claim(); process.Claim(computer); // break out of the loop claimed = true; } else { // the process that we Peek()ed above was already claimed so discard it // and go around the loop again processQueue.Dequeue(); } } } else { // there's no point in continuing to look for a process for the waiter // since it has been claimed by someone else. // The process we Peek()ed is left in the queue for the next // waiter to match return(true); } } } // there were no unclaimed processes, so add the waiter to the queue of // waiting computers if (!claimed) { waiterQueue.Enqueue(waiter); } } // exit the lock before triggering the wakeup of the computer if (claimed) { // this pairs the process with the computer waiter.Dispatch(process); return(true); } else { return(false); } }
/// <summary> /// add a waiting computer. If there is an unclaimed process waiting, the /// process will be assigned to the computer and the computer's Task will be /// unblocked. Returns true if the waiter has been matched (by this call or /// another asynchronous event in the meantime). Returns false if the computer /// still needs to be matched. /// </summary> /// <param name="waiter">holder for the waiting computer</param> /// <returns></returns> public bool AddWaiter(ProcessWaiter waiter) { // process will exit the lock holding the value of the newly-claimed process, if // any. process may be non-null exiting the lock even if there was no // unclaimed process; the claimed flag below disambiguates Process process = null; // claimed will exit the lock set to true if and only if there was an unclaimed // waiter, in which case waiter will be set to the value of the waiter bool claimed = false; // lock ordering discipline is Queue first, then waiter, then process lock (this) { if (!active) { // the queue has been shut down so don't accept another waiter lock (waiter) { if (waiter.Unclaimed) { waiter.Claim(); // this will make us Dispatch the waiter with a null process below // which is correct since the queue has been shut down, and will cause // the waiting computer's commandloop to exit if it hasn't already claimed = true; } } } // even if there are processes, they may have been claimed by other computers // already, so use a loop here while (active && processQueue.Count > 0 && !claimed) { // get the next available process; don't dequeue it yet because // we have to wait until we acquire the locks below to figure out // if it's going to be matched to anything process = processQueue.Peek(); // lock ordering discipline is Queue first, then waiter, then process lock (waiter) { if (waiter.Unclaimed) { // lock ordering discipline is Queue first, then waiter, then process lock (process) { // another queue might have turned up and claimed the Process // while we were dithering; matching a process to a computer // must be done while both are locked if (process.Unclaimed) { // remove the process from the queue and match it to the computer processQueue.Dequeue(); var computer = waiter.Claim(); process.Claim(computer); // break out of the loop claimed = true; } else { // the process that we Peek()ed above was already claimed so discard it // and go around the loop again processQueue.Dequeue(); } } } else { // there's no point in continuing to look for a process for the waiter // since it has been claimed by someone else. // The process we Peek()ed is left in the queue for the next // waiter to match return true; } } } // there were no unclaimed processes, so add the waiter to the queue of // waiting computers if (!claimed) { waiterQueue.Enqueue(waiter); } } // exit the lock before triggering the wakeup of the computer if (claimed) { // this pairs the process with the computer waiter.Dispatch(process); return true; } else { return false; } }
/// <summary> /// add a schedulable process. If there is an unclaimed computer waiting, the /// process will be assigned to the computer and the computer's Task will be /// unblocked. Returns true if the process has been matched (by this call or /// another asynchronous event in the meantime). Returns false if the process /// still needs to be matched. /// </summary> public bool AddProcess(Process process) { // waiter will exit the lock holding the value of the newly-claimed waiter, if // any. waiter may be non-null exiting the lock even if there was no // unclaimed waiter; the claimed flag below disambiguates ProcessWaiter waiter = null; // claimed will exit the lock set to true if and only if there was an unclaimed // waiter, in which case waiter will be set to the value of the waiter bool claimed = false; // lock ordering discipline is Queue first, then waiter, then process lock (this) { // if we are shutting down, return immediately if (!active) { return(false); } // even if there are waiters, they may have been claimed by processes // already, so use a loop here while (waiterQueue.Count > 0 && !claimed) { // get the next available waiter; don't dequeue it yet because // we have to wait until we acquire the locks below to figure out // if it's going to be matched to anything waiter = waiterQueue.Peek(); // lock ordering discipline is Queue first, then waiter, then process lock (waiter) { if (waiter.Unclaimed) { // lock ordering discipline is Queue first, then waiter, then process lock (process) { // another queue might have turned up and claimed the Process // while we were dithering; matching a process to a computer // must be done while both are locked if (process.Unclaimed) { // remove the waiter from the queue and match it to the process waiterQueue.Dequeue(); var computer = waiter.Claim(); process.Claim(computer); // break out of the loop claimed = true; } else { // there's no point in continuing to try to add the process // since it has been claimed by someone else. // The waiter we Peek()ed is left in the queue for the next // process to match return(true); } } } else { // the waiter that we Peek()ed above was already claimed so discard it // and go around the loop again waiterQueue.Dequeue(); } } } // there were no unclaimed waiters, so add the process to the queue of // schedulable items while we're holding the queue lock if (!claimed) { lock (process) { // let the process know it has been added to another queue process.IncrementQueueCount(); } processQueue.Enqueue(process); } } // exit the lock before triggering the wakeup of the computer if (claimed) { // this pairs the process with the computer waiter.Dispatch(process); return(true); } else { return(false); } }