7

Il titolo dice tutto. C'è qualcosa che non va con await Task.Run(() => semaphore.WaitOne());? System.Threading.Semaphore non è thread-affine, quindi non penserei che ci sarebbe un problema. So che la classe SemaphoreSlim è disponibile, ma devo eseguire la sincronizzazione tra processi e SemaphoreSlim non lo fa.C'è qualcosa di sbagliato nell'attesa Task.Run (() => semaphore.WaitOne())?

Oppure/posso creare il mio tipo personalizzato di WaitHandle?

+5

Non c'è tecnicamente alcun problema a fare questo. Se si dovrebbe fare questo o meno dipende da molti più dettagli non specificati nel tuo post. –

+2

L'operazione sottostante è intrinsecamente asincrona, eppure si sta eseguendo un thread del thread thread in modo asincrono sull'operazione asincrona in modo che sia possibile indicare in modo asincrono quando si è finito. Questo è generalmente di scarsa progettazione e dovrebbe essere evitato se possibile. È un segno che probabilmente non dovresti usare "Semaphore" in primo luogo. – Servy

+0

Indica un errore da parte dell'utente o un design discutibile. Sospetto che il primo - tu dici che "devi fare la sincronizzazione tra processi" ma questo non sincronizzerà nulla. Se il processo che chiama 'WaitOne' in realtà ha bisogno di sapere quando viene segnalato il semaforo, perché non attende in modo sincrono? Se non ha bisogno di sapere, perché avere il semaforo? –

risposta

4

Se stai cercando di mantenere l'interfaccia utente sensibile in attesa che il semaforo qui, potrebbe avere senso, ma c'è un problema: "Semaphores don't have owners". Se si condivide il semaforo tra due processi e l'altro si blocca senza chiamare Semaphore.Release(), , la proprietà sulla risorsa condivisa verrà persa. Il processo rimanente potrebbe non essere in grado di acquisirlo di nuovo.

IMO, la semantica Mutex sarebbe più appropriata qui, ma con Mutex avresti bisogno di affinità di thread. Forse, è possibile acquisire il mutex, accedere alla risorsa e rilasciarlo sullo stesso thread:

await Task.Factory.StartNew(() => 
{ 
    mutex.WaitOne(); 
    try 
    { 
     // use the shared resource 
    } 
    finally 
    { 
     mutex.ReleaseMutex(); 
    } 
}, TaskCreationOptions.LongRunnning); 

Se questo non è possibile (ad esempio, perché è necessario accedere alla risorsa condivisa sul thread dell'interfaccia utente principale), si potrebbe usa un thread dedicato per il mutex. Questo può essere fatto con uno schedulatore di attività personalizzato, ad es. di StaTaskScheduler con numberOfThreads:1 Stephen Toub (il filo di supporto non deve essere fatta STA in questo caso):

using (var scheduler = new StaTaskScheduler(numberOfThreads: 1)) 
{ 
    await Task.Factory.StartNew(
     () => mutex.WaitOne(), 
     CancellationToken.None, 
     TaskCreationOptions.None, 
     scheduler); 
    try 
    { 
     // use the shared resource on the UI thread 
    } 
    finally 
    { 
     Task.Factory.StartNew(
      () => mutex.ReleaseMutex(), 
      CancellationToken.None, 
      TaskCreationOptions.None, 
      scheduler).Wait(); 
    } 
} 

Aggiornato, se siete preoccupati per WinRT (vale a dire, .NET for Windows Store Apps) o Windows Phone, quindi Task.Factory.StartNew w/TaskCreationOptions.LongRunning è ancora lì, è possibile utilizzarlo al posto di new Thread() con StaTaskScheduler o qualcosa come il mio ThreadWithSerialSyncContext ogni volta che è necessario un thread in background con affinità.

+0

Bella soluzione, ma non penso che funzioni per me.Non riesco a usare un 'mutex' perché ho bisogno di aspettare alcuni compiti mentre ho acquisito il semaforo, e quindi i lock serrati sono un no-go. Anche usare 'Wait()' o 'RunSynchronously()' non è un'opzione. La soluzione 'StaTaskScheduler' che hai proposto sembra buona, ma sfortunatamente, nell'ultima iterazione delle API WinRT, la classe' Thread' non esiste. Escludendo un hard reset del sistema (che cancellerebbe comunque il semaforo), se avvolgo il codice sincronizzato in un tentativo/finalmente, ci sarebbe qualche possibilità di un semaforo abbandonato? –

+0

@ZaneKaminski, se si bilancia attentamente 'WaitOne' /' Release' con 'try' /' finally' dappertutto, si dovrebbe andare bene con questo approccio. – Noseratio

+0

@ZaneKaminski, controlla anche il mio aggiornamento relativo a WinRT. – Noseratio