Por que é necessário bloquear a fila neste exemplo

Tenho o exemplo mostrado abaixo. Não consigo descobrir porque é que o are também está bloqueado para a fila, enquanto os dois algoritmos coerentes estão completamente bloqueados usando o mesmo objecto.

Diz-se que o bloqueio da fila é necessário.

using System;
using System.Threading;
using System.Collections;

public class CrudeThreadPool
{
    static readonly int MaxWorkThreads = 4;
    static readonly int WaitTimeout = 2000;

    public delegate void WorkDelegate();

    public CrudeThreadPool() {
        stop = false;
        workLock = new Object();
        workQueue = new Queue();
        threads = new Thread[ MaxWorkThreads ];

        for( int i = 0; i < MaxWorkThreads; ++i ) {
            threads[i] =
                new Thread( new ThreadStart(this.ThreadFunc) );
            threads[i].Start();
        }
    }

    private void ThreadFunc() {
        lock( workLock ) {
            do {
                if( !stop ) {
                    WorkDelegate workItem = null;
                    if( Monitor.Wait(workLock, WaitTimeout) ) {

                        lock( workQueue.SyncRoot ) {
                            workItem =
                                (WorkDelegate) workQueue.Dequeue();
                        }
                        workItem();
                    }
                }
            } while( !stop );
        }
    }

    public void SubmitWorkItem( WorkDelegate item ) {
        lock( workLock ) {
            lock( workQueue.SyncRoot ) {
                workQueue.Enqueue( item );
            }

            Monitor.Pulse( workLock );
        }
    }

    public void Shutdown() {
        stop = true;
    }

    private Queue         workQueue;
    private Object        workLock;
    private Thread[]      threads;
    private volatile bool stop;
}

public class EntryPoint
{
    static void WorkFunction() {
        Console.WriteLine( "WorkFunction() called on Thread {0}",
                       Thread.CurrentThread.ManagedThreadId );
    }

    static void Main() {
        CrudeThreadPool pool = new CrudeThreadPool();
        for( int i = 0; i < 10; ++i ) {
            pool.SubmitWorkItem(
              new CrudeThreadPool.WorkDelegate(
                                 EntryPoint.WorkFunction) );
        }

        Thread.Sleep( 1000 );

        pool.Shutdown();
    }
}
Qual é a razão para bloquear a fila?

Author: Ucho, 2016-05-15

1 answers

A fechadura interna não é realmente necessária porque enquanto a espera não for atingida novamente a fechadura será mantida e bloqueará todos os produtores. Portanto, isto deve funcionar:
private void ThreadFunc() {
   do {
        if( !stop ) {
            WorkDelegate workItem = null;
            lock( workLock ) {
                if( Monitor.Wait(workLock, WaitTimeout) ) {
                    workItem = (WorkDelegate) workQueue.Dequeue();
                }
            }
            if (workItem != null) workItem();
        }
    } while( !stop );
}

public void SubmitWorkItem( WorkDelegate item ) 
{
    lock( workLock ) {
        workQueue.Enqueue( item );

        Monitor.Pulse( workLock );
    }
}

O site de Joseph Albahari é uma referência incrível para cenários de rosca. Embora este seja um cenário clássico de produtor/consumidor, eu recomendaria que você usasse um Bloqueio de recolha .

 1
Author: Slugart, 2016-05-15 20:37:56