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?
2
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