2009-03-11 15 views
6

Necesito un bloqueo simple de "uno a la vez" en una sección de código. Considere la función func que se puede ejecutar desde varios subprocesos:Sincronización simple de subprocesos

void func() 
{ 
    // locking/mutex statement goes here 
    operation1(); 
    operation2(); 
    // corresponding unlock goes here 
    operation3(); 
} 

necesito para asegurarse de que operation1operation2 y se ejecutan siempre "juntos". Con C# usaría un simple bloque lock alrededor de estas dos llamadas. ¿Cuál es el equivalente de C++/Win32/MFC?

Probablemente algún tipo de Mutex?

Respuesta

19

Las secciones críticas funcionarán (son más livianas que las de exclusión mutua) InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection y DeleteCriticalSection son las funciones que se deben buscar en MSDN.

void func() 
{ 
    // cs previously initialized via InitializeCriticalSection 
    EnterCriticalSection(&cs); 
    operation1(); 
    operation2(); 
    LeaveCriticalSection(&cs); 
    operation3();} 
} 

EDIT: Las secciones críticas son más rápidos que los mutex ya que las secciones críticas son principalmente primitivas modo de usuario - en el caso de una adquisición uncontended (por lo general el caso común) no hay ninguna llamada al sistema en el núcleo, y la adquisición de toma del orden de docenas de ciclos. Un cambio de kernel es más caro (del orden de cientos de ciclos). La única vez que las secciones críticas llaman al kernel es para bloquear, lo que implica esperar en una primitiva del kernel (ya sea mutex o evento). La adquisición de un mutex siempre implica una llamada al kernel y, por lo tanto, los pedidos de magnitud son más lentos. Sin embargo, las secciones críticas solo se pueden usar para sincronizar recursos en un proceso. Para sincronizar en múltiples procesos, se necesita un mutex.

+0

Correcto hasta el momento, pero hasta donde yo sé, CriticalSections usa mutexes internamente, por lo que no hay un beneficio de rendimiento. –

+0

Y luego, para la seguridad de las excepciones, podría incluir cs en una clase; ver RAII. – Reunanen

+0

(Dado que la pregunta es sobre C++) – Reunanen

2

Puede probar esto:

void func() 
{ 
    // See answer by Sasha on how to create the mutex 
    WaitForSingleObject (mutex, INFINITE); 
    operation1(); 
    operation2(); 
    ReleaseMutex(mutex); 
    operation3(); 
} 
+0

WaitForSingleObject es más lento. CriticalSections puede tomar un recuento de vueltas y girará durante un tiempo antes de caer en WaitForSingleObject. ver http://msdn.microsoft.com/en-us/library/ms683476(VS.85).aspx InitializeCriticalSectionAndSpinCount Función –

6

El mejor método sería el uso de una sección crítica, utilizar EnterCriticalSection y LeaveCriticalSection. La única parte difícil es que primero debe inicializar una sección crítica con InitializeCriticalSection. Si este código está dentro de una clase, ponga la inicialización en el constructor y la estructura de datos CRITICAL_SECTION como miembro de la clase. Si el código no es parte de una clase, es probable que deba utilizar un sistema global o algo similar para garantizar que se inicialice una vez.

6
  1. utilizando MFC:

    1. definir un objeto de sincronización. (Mutexto o sección crítica)

      1.1 Si varios subprocesos pertenecientes a un proceso diferente entran en el func(), entonces use CMutex.

      1.2. Si varios hilos del mismo proceso entran en el func() entonces use CCriticalSection.

    2. CSingleLock se puede utilizar para facilitar el uso de objetos de sincronización.

digamos que hemos definido sección crítica

CCriticalSection m_CriticalSection; 
    void func() 
    { 
     // locking/mutex statement goes here 
     CSingleLock aLock(&m_CriticalSection, **TRUE**); 
     // TRUE indicates that Lock aquired during aLock creation. 
     // if FALSE used then use aLock.Lock() for locking. 

     operation1(); 
     operation2(); 
      // corresponding unlock goes here 
      aLock.Unlock(); 
     operation3(); 
    } 

EDIT: Consulte el artículo de MSDN VC++: Multithreading with C++ and MFC Classes y Multithreading: How to Use the Synchronization Classes

25

fijación Michael solution anteriormente.

La solución Michael es perfecta para aplicaciones C. Pero cuando se usa en C++, se desaconseja este estilo debido a la posibilidad de excepciones. Si ocurre una excepción en operation1 u operation2, la sección crítica no se dejará correctamente y todos los demás hilos bloquearán la espera.

// Perfect solutiuon for C applications 
void func() 
{ 
    // cs previously initialized via InitializeCriticalSection 
    EnterCriticalSection(&cs); 
    operation1(); 
    operation2(); 
    LeaveCriticalSection(&cs); 
    operation3();} 
} 

// A better solution for C++ 
class Locker 
{ 
    public: 
    Locker(CSType& cs): m_cs(cs) 
    { 
     EnterCriticalSection(&m_cs); 
    } 
    ~Locker() 
    { 
     LeaveCriticalSection(&m_cs); 
    } 
    private: 
     CSType& m_cs; 
} 
void func() 
{ 
    // cs previously initialized via InitializeCriticalSection 
    { 
     Locker lock(cs); 
     operation1(); 
     operation2(); 
    } 
    operation3(); 
} 
+0

+1 mejor práctica de RAII .. – deepdive

+0

Arte de la programación. Muy elegante. Es más fácil distinguir bloques de secciones críticas y menos propensos a cometer errores. :-) – StanE

+0

Las mejores respuestas de todos. :) – Mak

Cuestiones relacionadas