7

Der Titel sagt alles. Ist etwas falsch mit await Task.Run(() => semaphore.WaitOne());? System.Threading.Semaphore ist nicht Thread-affine, also würde ich nicht denken, dass es ein Problem geben würde. Ich weiß, dass die SemaphoreSlim Klasse verfügbar ist, aber ich muss die prozessübergreifende Synchronisierung durchführen, und SemaphoreSlim tut das nicht.Ist etwas falsch mit warten Task.Run (() => semaphore.WaitOne())?

Oder kann/sollte ich meinen eigenen benutzerdefinierten Typ von WaitHandle erstellen?

+5

Es ist technisch kein Problem, dies zu tun. Ob Sie dies tun sollten oder nicht, hängt von vielen weiteren Details ab, die in Ihrem Post nicht angegeben sind. –

+2

Die zugrunde liegende Operation ist inhärent asynchron, und dennoch wartet ein Threadpool-Thread synchron auf den asynchronen Vorgang, sodass Sie asynchron angeben können, wann Sie fertig sind. Dies ist im Allgemeinen ein schlechtes Design und sollte wenn möglich vermieden werden. Es ist ein Zeichen, dass Sie "Semaphore" wahrscheinlich nicht verwenden sollten. – Servy

+0

Dies deutet entweder auf einen Fehler oder auf ein fragwürdiges Design hin. Ich vermute, dass Ersteres - Sie sagen, Sie müssen "Cross-Prozess-Synchronisation" tun, aber das wird nicht wirklich etwas synchronisieren. Wenn der Prozess, der 'WaitOne' aufruft, tatsächlich wissen muss, wann der Semaphor signalisiert wird, warum wartet er nicht synchron? Wenn es nicht wissen muss, warum überhaupt das Semaphor? –

Antwort

4

Wenn Sie versuchen, die Benutzeroberfläche, die auf zu halten, während hier für die Semaphore warten, könnte es Sinn machen, aber es gibt einen Haken: "Semaphores don't have owners". Wenn Sie den Semaphor zwischen zwei Prozessen freigeben und der andere Prozess abstürzt, ohne Semaphore.Release(), aufzurufen, geht die Eigentumsrechte an der freigegebenen Ressource verloren. Der verbleibende Prozess ist möglicherweise nicht in der Lage, es erneut zu erfassen.

IMO, die Mutex Semantik wäre hier angemessener, aber mit Mutex würden Sie Thread-Affinität benötigen. Vielleicht können Sie die Mutex erwerben, auf die Ressource zugreifen und sie auf dem gleichen Thread Mitteilung:

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

Wenn das nicht möglich ist (zB weil Sie die gemeinsam genutzte Ressource auf dem Haupt-UI-Thread zugreifen müssen), könnten Sie Verwenden Sie einen dedizierten Thread für den Mutex. Dies kann mit einem benutzerdefinierten Aufgabenplaner, z.B. Stephen Toub der StaTaskScheduler mit numberOfThreads:1 (der Helfer-Thread muss nicht STA in diesem Fall gemacht werden):

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(); 
    } 
} 

aktualisiert, wenn Sie über WinRT betroffen sind (dh .NET for Windows Store Apps) oder Windows Phone, dann Task.Factory.StartNew w/TaskCreationOptions.LongRunning ist immer noch da, Sie können es anstelle von new Thread() mit StaTaskScheduler oder etwas wie meine ThreadWithSerialSyncContext verwenden, wenn Sie einen Hintergrund-Thread mit Affinität benötigen.

+0

Schöne Lösung, aber ich denke nicht, dass es für mich funktioniert.Ich kann keinen 'Mutex' verwenden, weil ich auf einige Aufgaben warten muss, während ich den Semaphor erworben habe, und so sind Thread-affine Sperren ein No-Go. Die Verwendung von 'Wait()' oder 'RunSynchronically()' ist ebenfalls keine Option. Die von Ihnen vorgeschlagene 'StaTaskScheduler'-Lösung klingt gut, aber leider ist in der neuesten Iteration der WinRT-APIs die' Thread'-Klasse nicht existent. Wenn ich den Hard-Reset des Systems (was den Semaphor sowieso deaktivieren würde) verhindern würde, würde ich, wenn ich den synchronisierten Code in einem try/final-Wrapper einpacke, die Möglichkeit eines verlassenen Semaphors haben? –

+0

@ZaneKaminski, wenn Sie 'WaitOne' /' Release' sorgfältig mit 'try' /' finally' überall ausbalancieren, sollten Sie mit diesem Ansatz zufrieden sein. – Noseratio

+0

@ZaneKaminski, überprüfen Sie auch mein Update in Bezug auf WinRT. – Noseratio