У меня есть сценарий где
несколько потоков продвигают данные по Очереди
ТОЛЬКО ОДИН поток обрабатывает данные с помощью кода ниже
код -
while ( Continue )
{
while ( queue.Count > 0 )
{
MyObj o = queue.Dequeue();
someProcess(o);
}
myAutoResetEvent.WaitOne();
}
Но иногда, очередь. Двухсторонняя очередь () возвращает пустой указатель в сценарии выше того, Что дает?
Вам необходимо прочитать это сообщение в блоге .
Кроме того, вот очень минимальный каркас «канала» для связи между потоками:
public class Channel<T>
{
private readonly Queue<T> _queue = new Queue<T>();
public void Enqueue(T item)
{
lock (_queue)
{
_queue.Enqueue(item);
if (_queue.Count == 1)
Monitor.PulseAll(_queue);
}
}
public T Dequeue()
{
lock (_queue)
{
while (_queue.Count == 0)
Monitor.Wait(_queue);
return _queue.Dequeue();
}
}
}
Вы говорите:
несколько потоков помещают данные в очередь
Метод Queue
не является потокобезопасным. Это означает, что работа выполняется внутри метода Enqueue
, который необходимо синхронизировать, если его вызывают несколько потоков. Простым примером может быть обновление свойства Count
. Можно с уверенностью сказать, что где-то в методе Enqueue
есть строка, которая выглядит примерно так:
++count;
Но, как мы все знаем, это не атомарная операция. На самом деле это больше похоже на это (с точки зрения того, что на самом деле происходит ):
int newCount = count + 1;
count = newCount;
Итак, предположим, что счетчик
в настоящее время равен 5, а поток 1 проходит int newCount = count + 1
... затем поток 1 думает: «Хорошо, счет сейчас 5, так что я сделаю 6». Но самая следующая выполняемая операция - это когда поток 2 переходит к int newCount = count + 1
и думает о том же, что и поток 1 («теперь счетчик равен 6»). Итак, два элемента только что были добавлены в очередь, но счетчик только увеличился с 5 до 6.
Это просто очень простой пример того, как небезопасный для потоков метод, такой как Queue
может запутаться, когда доступ не синхронизирован. В нем конкретно не объясняется, что происходит в вашем вопросе; я просто хочу указать, что то, что вы делаете, не является потокобезопасным и вызовет неожиданное поведение .
Вам нужно синхронизировать доступ к очереди. Поместите операторы lock
вокруг всех участков кода, которые обращаются к очереди (как для чтения, так и для записи). Если вы обращаетесь к очереди одновременно из нескольких потоков, внутренние структуры могут быть повреждены, и может произойти что угодно.
Как указано в комментарии, ссылка _ на
недоступна с геймпада, если не указан соответствующий вспомогательный модуль, но url _ для
имеет значение. Поэтому я бы сделал почти то, что сказала Эмили, за исключением использования url _ для
вместо жесткого кодирования URL.
например. если задание было определено как ресурс в ваших маршрутах:
link = "<a href=\"#{url_for(update)}\">#{update.id}</a>"
flash[:notice] = "Created job number #{link}"
-121--1838576- Почему бы просто не использовать GLIB?
Среди множества других вещей он имеет библиотечные функции для разбора INI-файлов, таких как файлы конфигурации:
https://developer.gnome.org/glib/stable/glib-Key-value-file-parser.html
Кроме того, что он также поддерживает типы данных (списки, хэштаблы, последовательности,
Для меня это самая полезная библиотека Си, и мне нужно иметь очень хороший повод написать программу Си без использования этой библиотеки.
-121--2263933-Guffa правильна, при использовании нескольких потоков для чтения и записи в очередь возникнут проблемы, поскольку очередь < T > не является безопасной для потока.
Если вы используете .NET 4, используйте класс ConcurrentQueue < T > , который безопасен для потоков. Если вы не находитесь на .NET 3 или ранее, вы можете либо выполнить собственную блокировку, как указал Гуффа, либо использовать библиотеку стороннего производителя.
Почему вы не решаете проблему таким образом?
while (IsRunning)
{
do
{
MyObj myObj = queue.Dequeue();
if (myObj != null)
{
DoSomethingWith(myObj);
}
} while (myObj != null);
myAutoResetEvent.WaitOne();
}
Хорошо, после прочтения комментария Эрвикерса и всех других ответов вы все в порядке, и я просто ложь. Поэтому , пожалуйста, не используйте приведенный выше код в многопоточном контексте .
Убедитесь, что ничего не помещает нулевые
значения в очередь. null
разрешены как значения в очереди. Кроме того, согласно этого документа , только статические элементы Queue
являются потокобезопасными, поэтому будьте осторожны при чтении и записи между потоками.
Если вы используете неуниверсальную очередь (я не рекомендую ее использовать), вы можете использовать метод Queue.Synchronized для получения потока- безопасная оболочка:
Queue queue = Queue.Synchronized(new Queue());
В противном случае вам следует позаботиться о блокировке, как предлагают другие.