C # многопоточность - PullRequest
       13

C # многопоточность

4 голосов
/ 14 мая 2009

Посмотрите на код ниже. Предположим, что это ВЕСЬ класс. Я не пропустил ЛЮБОЙ код. Это буквально все, что он делает.

Если я создаю экземпляр этого класса в цикле моей основной программы и время от времени вызываю myExample.Add (что угодно), нужно ли мне беспокоиться о любых проблемах, вызванных отсутствием блокировки вокруг Dequeue () и Enqueue ()?

public class Example<T>
{
    private Queue<T> q = new Queue<T>();

    public Example()
    {
        new Thread(() => 
        {
            while (true) 
            {
                if (this.q.Count > 0)
                {
                    var item = this.q.Dequeue();
                }
                Thread.Sleep(1);
            }
        }).Start();
    }

    public void Add(T val)
    {
        this.q.Enqueue(val);
    }
}

Что произойдет, если this.q.Enqueue (val) вызывается одновременно с this.q.Dequeue ()?

Ответы [ 8 ]

8 голосов
/ 14 мая 2009

Короткая версия: вы должны синхронизировать доступ к очереди, если ожидаете, что она будет работать. В Count / Dequeue есть очевидные гонки потоков, но, что более важно, операция не гарантирована - внутреннее состояние может законно делать что угодно и, вероятно, повреждено.

Вы также хотели бы, в конце концов, выйти из потока ...

Чтобы написать очередь блокировки, см. Здесь: Создание блокировки Queue<T> в .NET .

2 голосов
/ 14 мая 2009

Это зависит. :) Если вы вызываете Пример с несколькими потоками, у вас будет условие состязания между проверкой количества очереди и очереди. Например ...

T1 Call Example
T2 Call Example
T2 check Q.Count > 0 (yes)
T1 check Q.count > 0 (yes)
T2 dequeue
T1 dequeue OOPS!

Если вы не приведете пример с несколькими потоками, у вас не возникнет проблем, поскольку вам все равно, что вы снимаете, а только то, что вы что-то снимаете. Если вам не безразлично то, что вы сняли, то снова возникнет проблема гонки между Add и Example.

1 голос
/ 14 мая 2009

MSDN говорит, что очередь не является потокобезопасной: http://msdn.microsoft.com/en-us/library/7977ey2c.aspx

1 голос
/ 14 мая 2009

Поскольку вы пишете в очередь с помощью метода Dequeue, вам необходимо заблокировать его. Очереди являются поточно-ориентированными для нескольких читателей, но не для нескольких пишущих.

1 голос
/ 14 мая 2009

Chris

Добавить личное статическое поле

readonly static object lockObject = new object();

заключить в очередь и поставить в очередь

lock(lockObject)
{
  //do stuff
}

для вашей лямбды поставь вне цикла

0 голосов
/ 14 мая 2009

Поскольку вы явно создаете отдельный поток, который изменяет очередь, вызывать Add () не всегда безопасно, независимо от того, из какого потока вы вызываете его.

Вам нужно заблокировать () блок операторов if, так как даже не безопасно вызывать q.Count, затем снова заблокировать в методе Add ().

0 голосов
/ 14 мая 2009

Я не понимаю, почему вы думаете, что это может быть безопасно.

Мое беспокойство / предположение заключается в том, что одновременный ввод в очередь и в очередь (из двух разных потоков) может повредить внутреннее состояние экземпляра очереди.

0 голосов
/ 14 мая 2009

Я предполагаю

this.queue.Enqueue(val);

вы имеете в виду

this.q.Enqueue(val);

Если это так, то да, вам нужно выполнить какую-то блокировку. Коллекции не являются потокобезопасными. Учитывая, что вы всегда удаляете из одного потока и всегда добавляете из другого, он МОЖЕТ работать нормально, но почему бы не проигнорировать его?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...