Example #1
0
        /// <summary>
        /// (asynchronously) block until there is a process available on the local queue, the rack queue
        /// or the cluster queue, then return that process. If ShutDown is called, this returns null
        /// immediately
        /// </summary>
        private async Task <Process> GetProcess()
        {
            // make a new waiter object to block on all the available queues until a Process is available
            var waiter = new ProcessWaiter(this);

            // get the actual blocker Task out of the waiter
            var blocker = waiter.Initialize();

            logger.Log("Computer " + name + " trying to find process on local queue");

            // try to match with an available Process in the local queue. If AddWaiter returns false, there
            // wasn't one, but by passing in waiter, we ensure that blocker will be unblocked if one
            // turns up. If Peek returns true there was already a waiting Process to be paired with,
            // blocker has been unblocked, and the await below will fall through immediately and return
            // the process; in this case don't bother to add the waiter to the rack and cluster queues.
            if (!localQueue.AddWaiter(waiter))
            {
                logger.Log("Computer " + name + " trying to find process on rack queue");

                // there was no local process, so try to match with an available Process in the rack queue.
                // If Peek returns false, there wasn't one, but by passing in waiter, we ensure that blocker
                // will be unblocked if one turns up. If Peek returns true then blocker is already unblocked
                // (because there was a Process in the rack queue, or by the localQueue we just put it in above)
                // and matched with a waiting process, and the await below will fall through immediately.
                if (!rackQueue.AddWaiter(waiter))
                {
                    logger.Log("Computer " + name + " trying to find process on cluster queue");

                    // there was no local or rack process, so try to match with an available Process in the
                    // cluster queue.
                    clusterQueue.AddWaiter(waiter);
                }
            }

            logger.Log("Computer " + name + " waiting for matched process");

            // we want to wait either for waiter to be matched with a Process in one of the three queues, or
            // for ShutDown to be called, so make an array of tasks and wait for the first one to be unblocked.
            TaskCompletionSource <Process> thisWaiter = GetAsyncFinishWaiter();
            var unblocked = await Task.WhenAny(blocker, thisWaiter.Task);

            RemoveAsyncFinishWaiter(thisWaiter);

            if (unblocked.Result != null)
            {
                logger.Log("Computer " + name + " matched process " + blocker.Result.Id);
            }
            else
            {
                logger.Log("Computer " + name + " unblocked by shutdown");
            }

            return(unblocked.Result);
        }
Example #2
0
        /// <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;
            }
        }
Example #3
0
        /// <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);
            }
        }
Example #4
0
        /// <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);
            }
        }