2011-11-14 24 views

Respuesta

11

Un AutoResetEvent es lo más parecido a un semáforo binario. Las personas que dicen "variables condicionales" no son incorrectas per se, pero las variables de condición se utilizan en situaciones similares, en lugar de ser objetos similares. Se puede implementar un AutoResetEvent (sin nombre) en la parte superior de las variables de condición:

#include <pthread.h> 
#include <stdio.h> 

class AutoResetEvent 
{ 
    public: 
    explicit AutoResetEvent(bool initial = false); 

    ~AutoResetEvent(); 
    void Set(); 
    void Reset(); 

    bool WaitOne(); 

    private: 
    AutoResetEvent(const AutoResetEvent&); 
    AutoResetEvent& operator=(const AutoResetEvent&); // non-copyable 
    bool flag_; 
    pthread_mutex_t protect_; 
    pthread_cond_t signal_; 
}; 

AutoResetEvent::AutoResetEvent(bool initial) 
: flag_(initial) 
{ 
    pthread_mutex_init(&protect_, NULL); 
    pthread_cond_init(&signal_, NULL); 
} 

void AutoResetEvent::Set() 
{ 
    pthread_mutex_lock(&protect_); 
    flag_ = true; 
    pthread_mutex_unlock(&protect_); 
    pthread_cond_signal(&signal_); 
} 

void AutoResetEvent::Reset() 
{ 
    pthread_mutex_lock(&protect_); 
    flag_ = false; 
    pthread_mutex_unlock(&protect_); 
} 

bool AutoResetEvent::WaitOne() 
{ 
    pthread_mutex_lock(&protect_); 
    while(!flag_) // prevent spurious wakeups from doing harm 
    pthread_cond_wait(&signal_, &protect_); 
    flag_ = false; // waiting resets the flag 
    pthread_mutex_unlock(&protect_); 
    return true; 
} 

AutoResetEvent::~AutoResetEvent() 
{ 
    pthread_mutex_destroy(&protect_); 
    pthread_cond_destroy(&signal_); 
} 


AutoResetEvent event; 

void *otherthread(void *) 
{ 
    event.WaitOne(); 
    printf("Hello from other thread!\n"); 
    return NULL; 
} 


int main() 
{ 
    pthread_t h; 
    pthread_create(&h, NULL, &otherthread, NULL); 
    printf("Hello from the first thread\n"); 
    event.Set(); 

    pthread_join(h, NULL); 
    return 0; 
} 

Sin embargo, si es necesario nombrado evento de reinicio automático, es probable que desee ver en los semáforos, y puede tener una traducción vez un poco más difícil tu codigo. De cualquier manera, miraría con cuidado la documentación para los subprocesos en su plataforma, las variables de condición y los eventos de reinicio automático no son los mismos y no se comportan igual.

0

Bueno, las probabilidades son más parecidas a un mutex: hay un número de personas que llaman buscando un recurso compartido, pero solo uno está permitido. En el caso de mutex, los llamantes intentarían obtener el mutex (por ejemplo, phtread_mutex_lock) , haga lo suyo, luego suelte (pthread_mutex_unlock) para que otra persona que llame pueda entrar.

+1

No, no es como un mutex. Es más como una variable de condición. – Gabe

3

Estoy seguro de que está buscando variables de condición. La respuesta aceptada a esta otra pregunta SO: Condition variables in C# - parece confirmarlo.

Véase p. this tutorial para obtener detalles sobre las variables de condición en los hilos POSIX.

+1

A Microsoft le gusta difuminar la distinción entre "bibliotecas", "plataformas" e "idiomas" en un gran embrollo que lo obliga a "comprar Microsoft". De hecho, la clase "AutoResetEvent" en .Net es una envoltura alrededor de la primitiva "Evento" en Win32, y análoga a "variables de condición" en PThreads. Aprenda PThreads para Linux. PThreads se puede utilizar en otras plataformas además de Linux, y con otros lenguajes (C, Python, etc.) además de C++. – paulsm4

+0

Solo me pregunto, ¿sería más fácil implementarlo usando boost: thread library? – derekhh

+0

@derekhh: No sé sobre "más fácil", las variables de condición son una construcción bastante simple, pero si ya está utilizando boost :: thread (que IMO es una opción perfectamente buena), use su variable de condición envoltorio, encajará perfectamente con el resto de su código: http://www.boost.org/doc/libs/1_47_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref –

2

Puede volver a implementar fácilmente objetos de Evento API de Win32 utilizando mutexes POSIX y variables de condición.

Sin embargo algunos de los comentarios anteriores me hace afirmar esto:

Una variable de condición es no análoga a un objeto de evento. Una variable de condición es fundamentalmente diferente de un evento en el sentido de que no tiene memoria o estado, en el sentido de que si no hay nadie bloqueado en la variable de condición en el momento de llamar a pthread_cond_signal o pthread_cond_broadcast, nada sucederá, en particular si un hilo viene más tarde para bloquear a través de pthread_cond_waitserá bloque.

I'l tratar de esbozar una aplicación de eventos de auto-restablecimiento rápido:

class event 
{ 
public: 
    event(): signalled_ (false) {} 

    void signal() 
    { 
    std::unique_lock<std::mutex> lock(mutex_); 
    signalled_ = true; 
    cond_.notify_one(); 
    } 

    void wait() 
    { 
    std::unique_lock<std::mutex> lock(mutex_); 

    while (!signalled_) 
     cond_.wait (lock); 
    signalled_ = false; 
    } 

protected: 
    std::mutex mutex_; 
    std::condition_variable cond_; 
    bool signalled_; 
}; 
1

Las variables condicionales son NOT equivalente a AutoResetEvent. Son el equivalente de los Monitores. La diferencia es crítica y puede causar interbloqueos si no se usa correctamente:

Imagine dos hilos A y B en un programa C#. A llama a WaitOne() y B llama a Set(). Si B ejecuta Set() antes de que A alcance la llamada a WaitOne(), no hay problema porque la señal enviada a AutoResetEvent() por Set() es persistente y permanecerá activa hasta que se ejecute WaitOne().

Ahora en C, imagine dos hilos C y D. C llama a wait(), D llama a notify(). Si C ya está esperando cuando D llama a notify() todo está bien. Si C no logró llegar a wait() antes de que D calls notify(), tenga un punto muerto porque la señal se pierde si nadie está esperando y el estado de la variable condicional aún está "desarmado".

Tenga mucho cuidado con esto.

1

El ejemplo de la documentación Tema/Condición de Boost es bastante similar a la ManualResetEvent normal y el uso AutoResetEvent: http://www.boost.org/doc/libs/1_53_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref
(he hecho algunos pequeños cambios para mayor claridad)

boost::condition_variable cond; 
boost::mutex mut; 
bool data_ready; 

void wait_for_data_to_process() 
{ 
    boost::unique_lock<boost::mutex> lock(mut); 
    while(!data_ready) 
    { 
     cond.wait(lock); 
    } 
} 

void prepare_data_for_processing() 
{ 
    { //scope for lock_guard 
     boost::lock_guard<boost::mutex> lock(mut); 
     data_ready=true; 
    } 
    cond.notify_one(); 
} 

Nota que las condiciones proporcionan la esperar/notificar el mecanismo de AutoResetEvent y ManualResetEvent, pero requiere un mutex para funcionar.

Cuestiones relacionadas