using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
public class OrderProcessor
private readonly ConcurrentDictionary<string, int> _inventory;
private readonly SemaphoreSlim _inventoryLock = new SemaphoreSlim(1, 1);
private int _successfulOrders = 0;
private int _failedOrders = 0;
private int _deadlocksDetected = 0;
private readonly ILogger _logger;
public OrderProcessor(Dictionary<string, int> initialInventory, ILogger logger)
if (initialInventory == null)
throw new ArgumentNullException(nameof(initialInventory), "Initial inventory cannot be null.");
_inventory = new ConcurrentDictionary<string, int>(initialInventory);
_logger = logger ?? throw new ArgumentNullException(nameof(logger), "Logger cannot be null.");
public async Task<(int successful, int failed, int deadlocks)> ProcessOrdersAsync(List<(string productId, int quantity)> orders)
throw new ArgumentNullException(nameof(orders), "Orders list cannot be null.");
var tasks = new List<Task>();
foreach (var order in orders)
tasks.Add(ProcessOrderWithRetryAsync(order.productId, order.quantity, 3));
await Task.WhenAll(tasks);
return (_successfulOrders, _failedOrders, _deadlocksDetected);
private async Task ProcessOrderWithRetryAsync(string productId, int quantity, int maxRetries)
if (string.IsNullOrEmpty(productId))
Interlocked.Increment(ref _failedOrders);
_logger.Log($"Invalid product ID. Order failed.");
Interlocked.Increment(ref _failedOrders);
_logger.Log($"Invalid quantity. Order failed.");
while (retries <= maxRetries)
if (await ProcessOrderAsync(productId, quantity))
if (retries <= maxRetries)
await Task.Delay(CalculateRetryDelay(retries));
Interlocked.Increment(ref _failedOrders);
_logger.Log($"Order for Product {productId}, Quantity: {quantity} failed after {maxRetries} retries.");
private async Task<bool> ProcessOrderAsync(string productId, int quantity)
var timeoutTask = Task.Delay(5000);
var lockTask = _inventoryLock.WaitAsync();
var completedTask = await Task.WhenAny(lockTask, timeoutTask);
if (completedTask == timeoutTask)
Interlocked.Increment(ref _deadlocksDetected);
_logger.Log($"Potential deadlock detected while trying to acquire lock for Product {productId}.");
if (!_inventory.ContainsKey(productId))
Interlocked.Increment(ref _failedOrders);
_logger.Log($"Product {productId} not found in inventory. Order failed.");
if (_inventory[productId] < quantity)
Interlocked.Increment(ref _failedOrders);
_logger.Log($"Insufficient inventory for Product {productId}. Order failed.");
_inventory.AddOrUpdate(productId, _inventory[productId] - quantity, (key, oldValue) => oldValue - quantity);
Interlocked.Increment(ref _successfulOrders);
_logger.Log($"Order for Product {productId}, Quantity: {quantity} processed successfully.");
_inventoryLock.Release();
private TimeSpan CalculateRetryDelay(int retryAttempt)
return TimeSpan.FromMilliseconds(Math.Pow(2, retryAttempt) * 100);
public Dictionary<string, int> GetInventorySnapshot()
return new Dictionary<string, int>(_inventory);
public static async Task Main(string[] args)
var initialInventory = new Dictionary<string, int>
var orders = new List<(string productId, int quantity)>
var logger = new ConsoleLogger();
var orderProcessor = new OrderProcessor(initialInventory, logger);
var (successful, failed, deadlocks) = await orderProcessor.ProcessOrdersAsync(orders);
Console.WriteLine($"Monitoring Statistics: Successful Orders: {successful} Failed Orders: {failed} Deadlocks Detected: {deadlocks}");
var finalInventory = orderProcessor.GetInventorySnapshot();
Console.WriteLine("Final Inventory:");
foreach (var item in finalInventory)
Console.WriteLine($"{item.Key}: {item.Value}");
void Log(string message);
public class ConsoleLogger : ILogger
public void Log(string message)
Console.WriteLine($"{DateTime.Now}: {message}");