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."); } } }); }
private void ProcessSingleCustomer() { var customer = customersQueue.DequeueCustomer(); // blocking operation var rnd = new Random(); var processDurationInSeconds = rnd.Next(minCashierProcessingTime, maxCashierProcessingTime + 1); taskFactory.StartNew(() => { var cashier = new Cashier($"Cashier-{Thread.CurrentThread.ManagedThreadId}", sleepService); try { 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 { maxCashiersSemaphore.Release(); } }); }