2009-06-30 14 views

risposta

16

Il più vicino che conosco è il Semaphore. Usalo con un conteggio "permesso" pari a 1, e aquire/release sarà più o meno lo stesso di quello che sai dallo ManualResetEvent.

Un semaforo inizializzato a uno, e che viene utilizzato tale da presentare solo in massimo un permesso disponibile, può servire come serratura mutua esclusione. Questo è più comunemente noto come semaforo binario , perché ha solo due stati : un permesso disponibile o zero autorizzazioni disponibili. Se utilizzato in questo modo , il semaforo binario ha la proprietà (a differenza di molti Blocco implementazioni), che il "blocco" può essere rilasciato da un thread diverso dal proprietario (come semafori non hanno alcuna nozione di proprietà). Ciò può essere utile in alcuni contesti specializzati , ad esempio il ripristino deadlock .

+0

Non penso che questo possa funzionare senza condizioni di competizione (supponendo che un thread non possa rilasciare un semaforo che non ha acquisito in precedenza) – ripper234

+1

Lo riprendo: dalla documentazione sembra che un semaforo possa essere rilasciato senza mai prenderlo. – ripper234

+3

Sì, è perché i semafori non hanno alcun concetto di proprietà. Sono praticamente contatori sincronizzati che hanno thread in attesa se il contatore è 0. – Lucero

3

base:

ManualResetEvent consente fili di comunicare tra loro mediante segnalazione. In genere, questa comunicazione riguarda un'attività che deve essere completata da prima che altri thread possano continuare.

da qui:

http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx

possibilmente desidera guardare le barriere nel pacchetto concorrenza Java - specificamente CyclicBarrier credo:

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CyclicBarrier.html

Blocca un numero fisso di thread fino a quando si verifica un evento particolare. Tutti i thread devono riunirsi in un punto di barriera .

+0

puoi fornire alcuni esempi di quella barriera? Non ho avuto l'esempio dalla documentazione. –

+0

Oh, ho trovato un articolo: http://tutorials.jenkov.com/java-util-concurrent/cyclicbarrier.html Quindi blocca fino a quando tutti i fili raggiungono la barriera (così si forma la massa critica) e poi deve continuare Piuttosto isntersting Ora saprò questa cosa. Sfortunatamente non è così utile per la domanda, ma arriva così, che ogni oggetto java è in attesa, shich è ManualResetEvent –

+0

@BogdanMart Ma si blocca automaticamente, il che significa che non è né "ManualResetEvent' né" AutoResetEvent'. –

8

Prova CountDownLatch con conteggio di uno.

CountDownLatch startSignal = new CountDownLatch(1); 
+6

Il problema con CountDownLatch è che non è riutilizzabile. Una volta che il latch raggiunge 0, non può più essere usato. Può essere sostituito con una nuova istanza di blocco, ma questo può creare condizioni di gara se non fatto bene. – ripper234

2

credo che il punto cruciale del .NET MRE è affinità di thread e la sua capacità di lasciare che tutti i thread in attesa passano attraverso quando Set viene chiamato. Ho trovato che l'uso del Semaphore funziona bene. Tuttavia, se ricevo 10 o 15 thread in attesa, mi imbatto in un altro problema. In particolare, si verifica quando viene chiamato Set. In .Net, tutti i thread in attesa vengono rilasciati. L'uso di un semphore non rilascia tutto. Così l'ho avvolto in una classe. NOTA: ho molta familiarità con .NET threading. Sono relativamente nuovo al threading e alla sincronizzazione di Java. Ciononostante, sono disposto a entrare e ottenere un feedback reale. Ecco la mia implementazione con assunzioni che un novizio Java renderebbe:

public class ManualEvent { 
private final static int MAX_WAIT = 1000; 
private final static String TAG = "ManualEvent"; 
private Semaphore semaphore = new Semaphore(MAX_WAIT, false); 

private volatile boolean signaled = false; 
public ManualEvent(boolean signaled) { 
    this.signaled = signaled; 
    if (!signaled) { 
     semaphore.drainPermits(); 
    } 
} 

public boolean WaitOne() { 
    return WaitOne(Long.MAX_VALUE); 
} 

private volatile int count = 0; 
public boolean WaitOne(long millis) { 
    boolean bRc = true; 
    if (signaled) 
     return true; 

    try { 
     ++count; 
     if (count > MAX_WAIT) { 
      Log.w(TAG, "More requests than waits: " + String.valueOf(count)); 
     } 

     Log.d(TAG, "ManualEvent WaitOne Entered"); 
     bRc = semaphore.tryAcquire(millis, TimeUnit.MILLISECONDS); 
     Log.d(TAG, "ManualEvent WaitOne=" + String.valueOf(bRc)); 
    } 
    catch (InterruptedException e) { 
     bRc = false; 
    } 
    finally { 
     --count; 
    } 

    Log.d(TAG, "ManualEvent WaitOne Exit"); 
    return bRc; 
} 

public void Set() { 
    Log.d(TAG, "ManualEvent Set"); 
    signaled = true; 
    semaphore.release(MAX_WAIT); 
} 

public void Reset() { 
    signaled = false; 
    //stop any new requests 
    int count = semaphore.drainPermits(); 
    Log.d(TAG, "ManualEvent Reset: Permits drained=" + String.valueOf(count)); 
} 

}

Si noti inoltre che sto praticamente scommettendo sul fatto che non c'è più di 1000 richieste in attesa di un rilascio in un dato momento.Rilasciando e acquisendo in lotti, sto tentando di rilasciare qualsiasi thread in attesa. Nota che la chiamata a WaitOne sta lavorando 1 permesso alla volta.

23
class ManualResetEvent { 

    private final Object monitor = new Object(); 
    private volatile boolean open = false; 

    public ManualResetEvent(boolean open) { 
    this.open = open; 
    } 

    public void waitOne() throws InterruptedException { 
    synchronized (monitor) { 
     while (open==false) { 
      monitor.wait(); 
     } 
    } 
    } 

    public boolean waitOne(long milliseconds) throws InterruptedException { 
    synchronized (monitor) { 
     if (open) 
     return true; 
     monitor.wait(milliseconds); 
     return open; 
    } 
    } 

    public void set() {//open start 
    synchronized (monitor) { 
     open = true; 
     monitor.notifyAll(); 
    } 
    } 

    public void reset() {//close stop 
    open = false; 
    } 
} 
+0

Sembra che non funzioni affatto: il thread uno chiama 'waitOne()' e blocca in 'monitor.wait()'. Thread due chiamate 'set' e blocchi su' synchronized (monitor) '. Questo è l'unico caso d'uso, giusto? Penso che sia ok se lasci uscire l'istruzione 'synchronized' in' set'. –

+3

@LimitedAtonement: in Java è necessario essere in un blocco sincronizzato per attendere un oggetto. Durante l'attesa, il blocco monitor di quell'oggetto viene rilasciato, quindi può essere acquisito in un'altra discussione. Vedi http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html –

+0

@WayneUroda Il mio male. Suppongo che non dovrei chiederti perché si deve stare in un blocco 'sincronizzato' per poi rilasciare il blocco chiamando' wait'. Sono sicuro che è vecchio come le colline;). –

Problemi correlati