2015-10-13 39 views
6

voglio controllare alcuni comportamenti di chiusura e non riesco a capire questo:Blocco su un tipo primitivo

static void Main(string[] args) 
{ 
    for (int i = 0; i < 10; i++) 
    { 
     Task.Factory.StartNew(() => 
     { 
      MultithreadedMethod(); 
     }); 
    } 

    Thread.Sleep(2000); 
    Console.WriteLine(count); 
} 

static int count = 0; 
private static readonly int sync = 5; 

public static void MultithreadedMethod() 
{ 
    if (Monitor.TryEnter(sync)) 
    { 
     count++; 
     Monitor.Exit(sync); 
    } 
} 

ho pensato che questo non dovrebbe funzionare a causa del fatto che sto facendo la sincronizzazione su un valore intero . Prima Boxing, quindi Unboxing e io dovremmo ottenere un System.Threading.SynchronizationLockException a causa della radice del blocco di sincronizzazione mancante (so che questo è specifico per i tipi di riferimento). Non mi prenderò gioco di me stesso, anche se questo funziona per poche iterazioni, non è veramente sincronizzato .. quindi, prendendo in considerazione la proprietà non atomica dell'operazione di incremento .. non otterrò risultati deterministici .. sono consapevole di questo.

In effetti, quando mi sbarazzerò di quel Thead.Sleep e metto un Wait sull'Account .. l'eccezione entra in vigore.

Task.Factory.StartNew(() => 
{ 
     MultithreadedMethod(); 
}).Wait(); 

penso un'eccezione dovrebbe essere gettato qui: Monitor.Exit(sync)

ma che cosa la prende?

Aggiornamento 1: immagine aggiunta.

enter image description here

+0

Quando eseguo il codice precedente, genera un'eccezione da "Esci". Sicuro che stai catturando l'eccezione dall'attività? –

+0

@PatrickHofman questo è tutto ciò che ho. Ho appena fatto la foto –

risposta

4

ma cosa lo cattura?

L'eccezione generata all'interno di un oggetto Task è implicitamente catturato all'interno che Task. Se non si accede alle proprietà Task.Exception o Task.Wait/Task.Result o await sull'attività restituita, l'eccezione verrà ingerita e non sarà possibile visualizzarla. Ecco perché l'utilizzo di Wait propaga l'eccezione e puoi vederlo nella console. Lo stesso accadrà se si utilizza Task.WaitAll per attendere il completamento di tutte le attività.

Se non si utilizza uno di questi, si può ancora vedere l'eccezione registrando a TaskScheduler.UnobservedTaskException:

static void Main(string[] args) 
{ 
    TaskScheduler.UnobservedTaskException += (s,e) => Console.WriteLine(e.Exception); 

    for (int i = 0; i < 10; i++) 
    { 
     Task.Factory.StartNew(() => 
     { 
      MultithreadedMethod(); 
     }); 
    } 

    Thread.Sleep(2000); 
    Console.WriteLine(count); 
} 

Resa:

Unobserved task exception

notare che questo codice ha ancora gara- condizioni dovute al fatto che in realtà non stiamo aspettando nessuno dei risultati a venire, il che potrebbe non accadere dopo un sonno di 2 secondi.

+1

@thumbmunkeys Anche dopo la correzione (grazie per averlo indicato) abbiamo ancora una condizione di competizione, quindi non * importa * molto, ma ha comunque apportato la modifica per renderla chiara. –

2

Quando eseguo il codice, vedo nella mia finestra di output:

Eccezione generata: 'System.Threading.SynchronizationLockException' in ConsoleApplication5.exe

I Immagino che non stai catturando le eccezioni provenienti dalle attività (e il tuo IDE non è impostato per interrompere quando non sono gestite). Invece di dormire il filo, provate questo:

List<Task> tasks = new List<Task>(); 
for (int i = 0; i < 21000; i++) 
{ 
    tasks.Add(Task.Factory.StartNew(() => 
    { 
     MultithreadedMethod(); 
    })); 
} 

Task.WaitAll(tasks.ToArray()); 

Il WaitAll mostrerà le eccezioni.

Problemi correlati