studio secretos programacion para infidelidad icono gratis edición descubrir desarrollo corazon con app aplicaciones aplicacion amantes c++ c multithreading concurrency thread-safety

c++ - secretos - cómo hacer que una aplicación sea segura?



manual de programacion android pdf (4)

Dos cosas:

1. Asegúrate de no usar globals. Si actualmente tiene elementos globales, hágalos miembros de una estructura de estado por subproceso y luego haga que el subproceso pase la estructura a las funciones comunes.

Por ejemplo, si comenzamos con:

// Globals int x; int y; // Function that needs to be accessed by multiple threads // currently relies on globals, and hence cannot work with // multiple threads int myFunc() { return x+y; }

Una vez que agreguemos en una estructura de estado, el código se convierte en:

typedef struct myState { int x; int y; } myState; // Function that needs to be accessed by multiple threads // now takes state struct int myFunc(struct myState *state) { return (state->x + state->y); }

Ahora puedes preguntar por qué no solo pasas xey como parámetros. La razón es que este ejemplo es una simplificación. En la vida real, su estructura de estado puede tener 20 campos y pasar la mayoría de estos parámetros 4-5 funciones hacia abajo resulta desalentador. Prefieres pasar un parámetro en lugar de muchos.

2. Si sus subprocesos tienen datos en común que necesitan ser compartidos, entonces debe buscar secciones críticas y semáforos. Cada vez que uno de tus hilos accede a los datos, necesita bloquear los otros hilos y luego desbloquearlos cuando haya terminado de acceder a los datos compartidos.

Pensé que el hilo seguro, en particular, significa que debe satisfacer la necesidad de múltiples hilos para acceder a los mismos datos compartidos. Pero, parece que esta definición no es suficiente.

¿Puede alguien enumerar las cosas que se deben hacer o cuidar para que la aplicación sea segura ? Si es posible, brinde una respuesta con respecto al lenguaje C / C ++.


Hay varias maneras en que una función puede ser segura para subprocesos.

Puede ser reentrante . Esto significa que una función no tiene estado y no toca ninguna variable global o estática, por lo que se puede invocar desde varios hilos simultáneamente. El término proviene de permitir que un hilo entre en la función mientras que otro hilo ya está dentro de él.

Puede tener una sección crítica . Este término se usa mucho, pero, francamente, prefiero los datos críticos . Se produce una sección crítica cada vez que su código toca datos que se comparten entre varios hilos. Por lo tanto, prefiero concentrarme en esos datos críticos.

Si usa un mutex correctamente, puede sincronizar el acceso a los datos críticos, protegiendo adecuadamente las modificaciones inseguras del hilo. Mutexes y bloqueos son muy útiles, pero con gran poder viene una gran responsabilidad. No debe bloquear el mismo mutex dos veces dentro del mismo subproceso (que es un autobloqueo). Debe tener cuidado si adquiere más de un mutex, ya que aumenta el riesgo de interbloqueo. Debe proteger constantemente sus datos con mutexes.

Si todas sus funciones son seguras para hilos y todos sus datos compartidos están adecuadamente protegidos, su aplicación debe ser segura para subprocesos.

Como dijo Crazy Eddie, este es un gran tema. Recomiendo leer hilos de refuerzo y usarlos en consecuencia.

advertencia de bajo nivel : los compiladores pueden reordenar las declaraciones, lo que puede romper la seguridad de los hilos. Con núcleos múltiples, cada núcleo tiene su propio caché, y necesita sincronizar correctamente los cachés para tener seguridad de hilos. Además, incluso si el compilador no reordena las declaraciones, el hardware podría. Entonces, la seguridad total y garantizada de los hilos no es posible en la actualidad. Sin embargo, puede obtener el 99.99% del camino, y se está trabajando con proveedores de compiladores y fabricantes de computadoras para solucionar esta persistente advertencia.

De todos modos, si estás buscando una lista de verificación para hacer una clase segura para subprocesos:

  • Identifique cualquier dato que se comparta entre hilos (si lo pierde, no puede protegerlo)
  • cree un miembro boost::mutex m_mutex y boost::mutex m_mutex cada vez que intente acceder a los datos de miembros compartidos (idealmente, los datos compartidos son privados para la clase, de modo que puede estar más seguro de que los está protegiendo adecuadamente).
  • limpiar los globales. Los globals son malos de todos modos, y buena suerte tratando de hacer algo seguro para hilos con globos globales.
  • Cuidado con la palabra clave static . En realidad no es seguro para subprocesos. Entonces, si intentas hacer un singleton, no funcionará bien.
  • Cuidado con el Paradigma de bloqueo de doble control. La mayoría de las personas que lo usan se equivocan en algunas formas sutiles, y es propenso a la rotura por la advertencia de bajo nivel.

Esa es una lista de verificación incompleta. Agregaré más si lo pienso, pero espero que sea suficiente para comenzar.


Una idea es pensar en su programa como un conjunto de hilos que conmutan a través de las colas. Cada subproceso tendría una cola, y estas colas se compartirían (junto con un método de sincronización de datos compartidos (como un mutex, etc.)) para todos los subprocesos.

Luego, "resuelva" el problema del productor / consumidor de la manera que desee evitar que las colas se desborden o se desborden. http://en.wikipedia.org/wiki/Producer-consumer_problem

Siempre y cuando mantenga sus hilos localizados, simplemente compartiendo datos con el envío de copias a través de la cola, y no acceda al hilo cosas inseguras como (la mayoría de las librerías gui y variables estáticas en múltiples hilos, entonces debería estar bien.


Si desea hacer un acceso exclusivo a los métodos de la clase, debe usar un bloqueo en estas funciones.

Los diferentes tipos de bloqueos:

Usando atomic_flg_lck:

class SLock { public: void lock() { while (lck.test_and_set(std::memory_order_acquire)); } void unlock() { lck.clear(std::memory_order_release); } SLock(){ //lck = ATOMIC_FLAG_INIT; lck.clear(); } private: std::atomic_flag lck;// = ATOMIC_FLAG_INIT; };

Usando atómico:

class SLock { public: void lock() { while (lck.exchange(true)); } void unlock() { lck = true; } SLock(){ //lck = ATOMIC_FLAG_INIT; lck = false; } private: std::atomic<bool> lck; };

Usando mutex:

class SLock { public: void lock() { lck.lock(); } void unlock() { lck.unlock(); } private: std::mutex lck; };

Solo para Windows :

class SLock { public: void lock() { EnterCriticalSection(&g_crit_sec); } void unlock() { LeaveCriticalSection(&g_crit_sec); } SLock(){ InitializeCriticalSectionAndSpinCount(&g_crit_sec, 0x80000400); } private: CRITICAL_SECTION g_crit_sec; };

El atómico y el atomic_flag mantienen el hilo en un recuento de vueltas. Mutex simplemente duerme el hilo. Si el tiempo de espera es demasiado largo, quizás sea mejor que duerma el hilo. El último " CRITICAL_SECTION " mantiene el hilo en un recuento de vueltas hasta que se consume un tiempo, luego el hilo se pone a dormir.

¿Cómo usar estas secciones críticas?

unique_ptr<SLock> raiilock(new SLock()); class Smartlock{ public: Smartlock(){ raiilock->lock(); } ~Smartlock(){ raiilock->unlock(); } };

Usando la expresión raii. El constructor para bloquear la sección crítica y el destructor para desbloquearlo.

Ejemplo

class MyClass { void syncronithedFunction(){ Smartlock lock; //..... } }

Esta implementación es segura para subprocesos y excepcional porque el bloqueo de variable se guarda en la pila, por lo que cuando se finaliza el alcance de la función (fin de la función o una excepción) se llamará al destructor.

Espero que esto te sea útil.

¡¡Gracias!!