потокобезопасный внутри потока работника - PullRequest
2 голосов
/ 08 ноября 2010

Мне интересно, как сделать внутри потока выполнения, чтобы быть потокобезопасным, позвольте мне объяснить это на примере:

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


public void Enqueue(ICommand command)
{
    this.queue.Enqueue(command);
    this.synchroHandler.Set();
}

private void Pipeline()
{
    while (true)
    {
        this.synchroHandler.WaitOne();

        while (this.queue.Count > 0)
        {
            ICommand command = this.queue.Dequeue();
            command.Execute();
        }
        // what if command will be enqueued between previous command - HERE

        // ... and this command HERE
        this.synchroHandler.Reset();
    }
}

public void Main()
{
    this.queue = new ThreadSafeQueue<ICommand>();
    this.computionHandler = new ManualResetEvent(false);
    Thread thread = new Thread(new ThreadStart(this.Pipeline));
    thread.Start();

    // start adding commands to pipeline
    this.Enqueue(command1);
    this.Enqueue(command2);
    ...
}

Допустим, моя реализация очереди является поточно-ориентированной, поэтому this.queue.Count, this.queue.Enqueue и this.queue.Dequeue используют одну и ту же блокировку. S показано в примере, если public Enqueue () будет вызван между "}" и this.synchroHandler.Reset (); поток будет в конечном итоге спящим, даже если у него есть один элемент в очереди (this.synchroHandler.Set () будет вызван непосредственно перед this.synchroHandler.Reset ()). Любая идея, как сделать эту схему потокобезопасной?

Ответы [ 3 ]

2 голосов
/ 08 ноября 2010

Извлечение BlockingCollection <T>, потокобезопасный производитель-потребитель в System.Collections.Concurrent пространство имен.

0 голосов
/ 09 ноября 2010

Можете ли вы изменить его на вращение?Таким образом, каждые 10 мс поток просыпается и проверяет, есть ли в очереди элемент, в противном случае он снова переходит в спящий режим.

while (true)
    {
        while (this.queue.Count > 0)
        {
            ICommand command = this.queue.Dequeue();
            command.Execute();
        }
        Thread.Sleep(10);
    }
0 голосов
/ 09 ноября 2010

Вы должны вызывать this.synchroHandler.Reset () сразу после WaitOne ().

Поэтому, если Queue вызывается до сброса, вы войдете в цикл while, и если он вызывается после того, как вы проверили queue.Count, при следующем вызове WaitOne () он сразу же вернется и перейдет в цикл while.

...