/// <summary> /// Enqueue a master job. A master job requires exclusive access to all chunks. /// </summary> /// <param name="work">The work to be executed by the job.</param> /// <param name="reserveQueue">Evaluates whether the job can be enqueued. If so, the master queue is reserved /// to indicate that this job is currently queued or executing.</param> /// <param name="unreserveQueue">Un-reserve the master queue to indicate that this job is no longer queued or /// executing.</param> /// <param name="canSkip">Indicates whether the job can be skipped.</param> /// <returns>True if the job was enqueued.</returns> public bool EnqueueMaster( Action work, Predicate<MasterJobQueue> reserveQueue, Action<MasterJobQueue> unreserveQueue, bool canSkip) { // Create the job var job = new MasterJob(work, unreserveQueue, canSkip, this.chunkQueues.Count + 10); job.IsPendingChanged += this.Job_IsPendingChanged; job.Completed += this.Job_Completed; // Enqueue the job if it can be reserved this.queuesLock.Enter(); try { // Reserve the master queue if (!reserveQueue(this.masterQueue)) { return false; } // Build the set of owners int i = 0; ChunkJobQueue[] chunkQueues = new ChunkJobQueue[this.chunkQueues.Count]; foreach (ChunkJobQueue queue in this.chunkQueues.Values) { chunkQueues[i++] = queue; } // Add the owners and enqueue the job job.AddOwners(this.masterQueue); job.AddOwners(chunkQueues); this.masterQueue.Enqueue(job); foreach (ChunkJobQueue queue in chunkQueues) { queue.Enqueue(job); } // Retain a reference to this master job this.masterQueueJobs.Add(job); } finally { this.queuesLock.Exit(); } return true; }
/// <summary> /// Initialise the job queue for the given chunk. /// </summary> /// <param name="chunk">The chunk.</param> /// <returns>The job queue.</returns> private ChunkJobQueue InitialiseQueue(Vector2I chunk) { var queue = new ChunkJobQueue(chunk, this.masterQueueJobs); queue.Idle += this.ChunkJobs_QueueIdle; this.chunkQueues.Add(chunk, queue); return queue; }
/// <summary> /// Enqueue a job which requires exclusive access to one or more chunks. This must be called between /// BeginEnqueueChunks and EndEnqueueChunks. /// </summary> /// <param name="work">The work to be executed by the job.</param> /// <param name="reserveQueue">Reserve each queue to indicate that this job is currently queued or executing. /// </param> /// <param name="unreserveQueue">Un-reserve each queue to indicate that this job is no longer queued or /// executing.</param> /// <param name="canSkip">Indicates whether the job can be skipped.</param> /// <param name="chunks">The chunks to which this job requires exclusive access.</param> public void EnqueueChunks( Action work, Action<ChunkJobQueue> reserveQueue, Action<ChunkJobQueue> unreserveQueue, bool canSkip, Vector2I[] chunks) { // Create the job var job = new ChunkJob(work, unreserveQueue, canSkip, chunks.Length); job.IsPendingChanged += this.Job_IsPendingChanged; job.Completed += this.Job_Completed; // Build the set of owners, checking whether the job can be enqueued ChunkJobQueue[] chunkQueues = new ChunkJobQueue[chunks.Length]; for (int i = 0; i < chunks.Length; i++) { chunkQueues[i] = this.GetOrInitialiseQueue(chunks[i]); } // Reserve the owner queues foreach (ChunkJobQueue queue in chunkQueues) { reserveQueue(queue); } // Add the owners and enqueue the job job.AddOwners(chunkQueues); foreach (ChunkJobQueue queue in chunkQueues) { queue.Enqueue(job); } }