Правильный способ получения результатов из блокирующей коллекции - PullRequest
0 голосов
/ 22 апреля 2019

У меня есть 50 объектов IMountCmd из одного или нескольких потоков, и я помещаю их в блокирующую коллекцию. Каждый выполняется, а некоторые получают результаты или ошибки. Они помещаются в ConcurrentDictionary, где я выполняю цикл для ContainsKey и возвращаю объекты. Кажется ли это потокобезопасным и правильным способом обработки очереди блокировки?

public class CmdGetAxisDegrees : IMountCommand
{
    public long Id { get; }
    public DateTime CreatedUtc { get; private set; }
    public bool Successful { get; private set; }
    public Exception Exception { get; private set; }
    public dynamic Result { get; private set; }
    private readonly AxisId _axis;

    public CmdGetAxisDegrees(long id, AxisId axis)
    {
        Id = id;
        _axis = axis;
        CreatedUtc = HiResDateTime.UtcNow;
        Successful = false;
        Queues.AddCommand(this);
    }

    public void Execute(Actions actions)
    {
        try
        {
            Result = actions.GetAxisDegrees(_axis);
            Successful = true;
        }
        catch (Exception e)
        {
            Successful = false;
            Exception = e;
        }
    }
}

 private static void ProcessCommandQueue(IMountCommand command)
    {
        command.Execute(_actions);
        if (command.Id > 0)
        {
            _resultsDictionary.TryAdd(command.Id, command);
        }
    }

public static IMountCommand GetCommandResult(long id)
    {
        IMountCommand result;
        while (true)
        {
            if (!_resultsDictionary.ContainsKey(id)) continue;
            var success = _resultsDictionary.TryRemove(id, out result);
            if (!success)
            {
                //log 
            }
            break;
        }
        return result;
    }

  static Queues()
    {
        _actions = new Actions();
        _resultsDictionary = new ConcurrentDictionary<long, IMountCommand>();
        _commandBlockingCollection = new BlockingCollection<IMountCommand>();
        Task.Factory.StartNew(() =>
        {
            foreach (var command in _commandBlockingCollection.GetConsumingEnumerable())
            {
                ProcessCommandQueue(command);
            }
        });
    }

public interface IMountCommand
{
    long Id { get; }
    DateTime CreatedUtc { get; }
    bool Successful { get; }
    Exception Exception { get; }
    dynamic Result { get; }
    void Execute(Actions actions);
}
...