c#System.InvalidOperationException用于创建队列的tyring

时间:2017-05-18 13:41:37

标签: c#

我正在尝试构建一个队列,以便在API给出生命迹象后将数据发送到API。

以下代码中的System.InvalidOperationException:

 private void sendHandler()
    {
        while (true)
        {
            if (!sendQueueActive && sendQueue.Count >= 1)
            {
                sendQueueActive = true;
                foreach (relays relays in sendQueue)
                {                        
                    dynamic result = IoLogikApiConnector.put("io/relay", relays);
                    int code = result.error.code;
                    if (code != 0)
                    {
                        _log.logErrorToApi("Cannot write to IoLogik", "Error code:" + result, _deviceID);
                        _device.logErrorToApi();
                        sendQueue.Remove(relays);
                    }
                    else
                    {

                        _device.logConnectedToApi();
                        sendQueue.Remove(relays);
                    }
                    sendQueueActive = false;

                }
            }
            else
            {
                Thread.Sleep(20);
            }
        }
    }

1 个答案:

答案 0 :(得分:2)

使用foreach时,您正在从队列中删除项目。绝不是一件好事。

最好写

using System.Linq;
using System.Collections.Generic;
using System.Collections;

private void sendHandler()
{
    while (true)
    {
        if (!sendQueueActive && sendQueue.Count >= 1)
        {
            sendQueueActive = true;

            // MAKE A COPY FIRST
            var sendQueueCopy = sendQueue.ToList();

            foreach (relays relays in sendQueueCopy)
            {                        
                dynamic result = IoLogikApiConnector.put("io/relay", relays);
                int code = result.error.code;
                if (code != 0)
                {
                    _log.logErrorToApi("Cannot write to IoLogik", "Error code:" + result, _deviceID);
                    _device.logErrorToApi();
                    sendQueue.Remove(relays);
                }
                else
                {

                    _device.logConnectedToApi();
                    sendQueue.Remove(relays);
                }
                sendQueueActive = false;

            }
        }
        else
        {
            Thread.Sleep(20);
        }
    }
}

但更好的是使用线程安全队列。

https://msdn.microsoft.com/en-us/library/dd997371(v=vs.110).aspx

以下是上述链接中的剪切和粘贴示例

        // A bounded collection. It can hold no more 
        // than 100 items at once.
        BlockingCollection<Data> dataItems = new BlockingCollection<Data>(100);


        // A simple blocking consumer with no cancellation.
        Task.Run(() => 
        {
            while (!dataItems.IsCompleted)
            {

                Data data = null;
                // Blocks if number.Count == 0
                // IOE means that Take() was called on a completed collection.
                // Some other thread can call CompleteAdding after we pass the
                // IsCompleted check but before we call Take. 
                // In this example, we can simply catch the exception since the 
                // loop will break on the next iteration.
                try
                {
                    data = dataItems.Take();
                }
                catch (InvalidOperationException) { }

                if (data != null)
                {
                    Process(data);
                }
            }
            Console.WriteLine("\r\nNo more items to take.");
        });

        // A simple blocking producer with no cancellation.
        Task.Run(() =>
        {
            while (moreItemsToAdd)
            {
                Data data = GetData();
                // Blocks if numbers.Count == dataItems.BoundedCapacity
                dataItems.Add(data);
            }
            // Let consumer know we are done.
            dataItems.CompleteAdding();
        });