private void FinishRemainingCustomers() { logger.Info("Store was closed. Finishing with the last remaining customers."); while (customersQueue.GetCustomersCount() > 0) { maxCashiersSemaphore.Wait(); // blocking operation ProcessSingleCustomer(); } }
private Action GetProcessCustomerAction(Cashier cashier, CancellationToken token) { return(() => { try { var customer = customersQueue.DequeueCustomer(); // blocking operation! var rnd = new Random(); var processDurationInSeconds = rnd.Next(minCashierProcessingTime, maxCashierProcessingTime + 1); cashier.ProcessCustomer(customer, processDurationInSeconds); // blocking operation! logger.Info($"{cashier.Name} finished processing customer at: {customer.Finished}. Number of waiting customers: {customersQueue.GetCustomersCount()}"); } catch (Exception e) { logger.Error($"Error in {cashier.Name} work: {e}"); } finally { // I issue a new task instaed of just calling this Action recursively, beacuse it will cause // the call stack to chain and eventually to cause an out of memory error. // The child task is, by deafult, detached from its parent task and therefore will not chain a call stack. if (!token.IsCancellationRequested) { taskFactory.StartNew(GetProcessCustomerAction(cashier, token), token); } else { logger.Info($"{cashier.Name} work was cancelled. Stopping."); } } }); }