Diseño de roscado de la base de datos -- # campo con multithreading campo con thread-safety camp codereview Relacionados El problema

Database threading design


4
vote

problema

Español

Soy nuevo para enhebrar y soy un desarrollador junior, así que supongo que hay muchos errores. Mi escenario es esto:

  • Mira en la base de datos
  • Si hay datos que deben ser enviados
    • Agregue los datos a la cola
  • si la cola no está vacía
    • envíe el siguiente mensaje y retírelo de la cola
    • Dormir 10 segundos
  • Si llegó un mensaje de otro hilo
    • deja de esperar e ir al siguiente mensaje en la cola
  • Si no llegó ningún mensaje de otro hilo
    • Volver al primer paso, pero haz esto solo 2 veces
    • Si un mensaje aún no ha llegado de otro hilo
      • pase al siguiente mensaje hasta que la cola esté vacía
  • Volver al primer paso

Estoy tratando de hacer esto así:

  private Thread ReceiveThread; private Thread SendThread; internal static Thread ServiceThread;   

estos 3 hilos:

  ReceiveThread = new Thread(ReceiveTask); ReceiveThread.Start(); ServiceThread = new Thread(SerAutoThread.SendServiceMsg); ServiceThread.Start(); SendThread = new Thread(SendTask); SendThread.Start();   

  class SerAutoThread {     internal static object[] NextService;     public static readonly object _locker = new object();     internal static Queue<object[]> Services;     internal static int sendingTime = 0;     private static DatabaseFirebird DB;     internal static void SendServiceMsg()     {         DB = new DatabaseFirebird();         DB.Open(ConnectionStr);         Services = new Queue<object[]>();         while (true)         {             if (Services.Count != 0)             {                 SetNextSerAndSend();             }             else             {                 CheckAndSetServices();             }         }     }       private static void SetNextSerAndSend()     {         NextService = Services.Dequeue();         for (int j = 0; j < 4; j++)         {             if (sendingTime == TRANSMITTED)             {                //pass to next msg                sendingTime = 0;                j = NEXTMSG;             }             else if (sendingTime < 3)             {                 sendingTime++;                 Byte[] data = SetNextPckage();                 DeviceManager.MessageSendQueue.PostItem(new SendMessage("UDPCmd",                 NextService[(int)NextMsg.DeviceId].ToString(),                  data, data.Length));                 MyDebug.WriteLine("Sended...");                 lock (_locker)                 {                     Monitor.Wait(_locker, TimeSpan.FromSeconds(10));                 }             }             else              {                 // pass to next msg                 j = NEXTMSG;             }         }     } }   

  private void ReceiveTask() {     ReceiveMessage receiveMsg;     while (true)     {         receiveMsg = Com.MessageReceiveQueue.GetItem(-1);         SerAutoThread.sendingTime = SerAutoThread.TRANSMITTED;         lock (SerAutoThread._locker)         {             Monitor.Pulse(SerAutoThread._locker);         }     } }   

   private void SendTask()  {      SendMessage msg;      while (true)      {          msg = MessageSendQueue.GetItem(-1);          String rtrn = PushData(msg);      }  }   

¿Es este hilo seguro o no? No estoy seguro de si algo está mal con el diseño o estoy haciendo algo mal en otros lugares.

y este no es mi código completo (para la comprensión). Cuando realmente ejecuto la aplicación, esto funciona bien. Ayer, solo los sistemas de gestión de la base de datos (Firebird) bloqueados. Luego detuve mi aplicación, dejó de que Firebird Server luego comenzó de nuevo y volvió a correr mi aplicación. Ahora está bien otra vez. No estoy usando hilos con entendimiento profundo. Así que me preocupa la seguridad del hilo.

¿Es posible para el Firebird Bloqueado en hilo?

Original en ingles

I am new to threading and I am a junior developer, so I guess there are many mistakes. My scenario is this:

  • look into the database
  • if there are data which should be sent
    • add the data to the queue
  • if queue is not empty
    • send the next message and remove it from the queue
    • sleep 10 seconds
  • if a message from another thread arrived
    • stop waiting and go to next message in queue
  • if no message from another thread arrived
    • go back to the first step, but do this only 2 times
    • if a message still hasn't arrived from another thread
      • pass to the next message until queue is empty
  • return to the first step

I am trying to do this like this:

private Thread ReceiveThread; private Thread SendThread; internal static Thread ServiceThread; 

These 3 threads:

ReceiveThread = new Thread(ReceiveTask); ReceiveThread.Start(); ServiceThread = new Thread(SerAutoThread.SendServiceMsg); ServiceThread.Start(); SendThread = new Thread(SendTask); SendThread.Start(); 

class SerAutoThread {     internal static object[] NextService;     public static readonly object _locker = new object();     internal static Queue<object[]> Services;     internal static int sendingTime = 0;     private static DatabaseFirebird DB;     internal static void SendServiceMsg()     {         DB = new DatabaseFirebird();         DB.Open(ConnectionStr);         Services = new Queue<object[]>();         while (true)         {             if (Services.Count != 0)             {                 SetNextSerAndSend();             }             else             {                 CheckAndSetServices();             }         }     }       private static void SetNextSerAndSend()     {         NextService = Services.Dequeue();         for (int j = 0; j < 4; j++)         {             if (sendingTime == TRANSMITTED)             {                //pass to next msg                sendingTime = 0;                j = NEXTMSG;             }             else if (sendingTime < 3)             {                 sendingTime++;                 Byte[] data = SetNextPckage();                 DeviceManager.MessageSendQueue.PostItem(new SendMessage("UDPCmd",                 NextService[(int)NextMsg.DeviceId].ToString(),                  data, data.Length));                 MyDebug.WriteLine("Sended...");                 lock (_locker)                 {                     Monitor.Wait(_locker, TimeSpan.FromSeconds(10));                 }             }             else              {                 // pass to next msg                 j = NEXTMSG;             }         }     } } 

private void ReceiveTask() {     ReceiveMessage receiveMsg;     while (true)     {         receiveMsg = Com.MessageReceiveQueue.GetItem(-1);         SerAutoThread.sendingTime = SerAutoThread.TRANSMITTED;         lock (SerAutoThread._locker)         {             Monitor.Pulse(SerAutoThread._locker);         }     } } 

 private void SendTask()  {      SendMessage msg;      while (true)      {          msg = MessageSendQueue.GetItem(-1);          String rtrn = PushData(msg);      }  } 

Is this thread-safe or not? I'm not sure if something is wrong with the design or I'm doing something wrong elsewhere.

And this is not my entire code (for understanding). When I actually run the app, this works fine. Yesterday just ones my Database management system (Firebird) locked. Then I stopped my app, stopped Firebird server then started again and ran my app again. Now it is ok again. I am not using threads with deep understanding. So I am worried about thread safety.

Is it possible for the thread-locked Firebird?

        
 
 

Lista de respuestas

2
 
vote

Esto se ve bastante bien conmigo. No soy tan bueno en los hilos, así que no comentaré por la seguridad del hilo, pero estas son algunas cosas que noté.

Esto está bien como lo es, pero es posible que desee considerar hacer esto un ternario:

  if (Services.Count != 0) {     SetNextSerAndSend(); } else {     CheckAndSetServices(); }   

Aquí está en forma ternaria:

  Services.Count == 0 ? CheckAndSetServices() : SetNextSerAndSend();   

No estoy seguro de cómo esto afectaría el rendimiento de su código, o si es importante que la variable permanezca igual, pero es bueno mantener siempre las variables en lo más ajustado como sea posible:

  private void SendTask() {     SendMessage msg;     while (true)     {         msg = MessageSendQueue.GetItem(-1);         String rtrn = PushData(msg);     } }   

Esto podría convertirse:

  private void SendTask() {     while (true)     {         SendMessage msg = MessageSendQueue.GetItem(-1);         String rtrn = PushData(msg);     } }   

El mismo principio se puede aplicar a ReceiveTask .

 

This looks pretty good to me. I am not that good at threads myself, so I won't comment on the thread safety, but these are a few things I noticed.

This is fine as it is, but you might want to consider making this a ternary:

if (Services.Count != 0) {     SetNextSerAndSend(); } else {     CheckAndSetServices(); } 

Here it is in ternary form:

Services.Count == 0 ? CheckAndSetServices() : SetNextSerAndSend(); 

I'm not sure how this would affect the performance of your code, or whether it is important that the variable stay the same, but it is good to always keep your variables in as tight a scope as possible:

private void SendTask() {     SendMessage msg;     while (true)     {         msg = MessageSendQueue.GetItem(-1);         String rtrn = PushData(msg);     } } 

This could possibly become:

private void SendTask() {     while (true)     {         SendMessage msg = MessageSendQueue.GetItem(-1);         String rtrn = PushData(msg);     } } 

The same principle can be applied to ReceiveTask.

 
 
   
   
1
 
vote

Tiene una situación clásica en la que se pueden acceder a múltiples hilos en la base de datos y se requieren dos operaciones (una lectura y una actualización) para hacer el trabajo.

Es posible hacer que tales esquemas funcionen, pero es un trabajo duro: necesitará una transacción alrededor de la operación de lectura / actualización y su código posiblemente necesitará manejar excepciones de puntos muertos. La depuración y la prueba del código de bloqueo es difícil, ya que rara vez sucederá.

Si solo está involucrado una aplicación, le sugiero que delegue las operaciones de la base de datos a una clase segura de hilos singleton. La sincronización de sus métodos asegurará que solo un hilo acceda a la base de datos en cualquier momento.

Si necesita la base de datos para implementar la seguridad de los hilos, considere establecer el nivel de aislamiento de transacción en serializado. Esto debería solucionar el problema a expensas del rendimiento.

 

You have a classic situation where multiple threads can access the database and two operations (a read and an update) are required to do the work.

It is possible to make such schemes work, but it is hard work - you will need a transaction around the read/update operation and your code will possibly need to handle deadlock exceptions. Debugging and testing the deadlock code is difficult, as it will seldom happen.

If only one application is involved, then I suggest you delegate database operations to a singleton thread-safe class. Synchronizing its methods will ensure that only one thread accesses the database at any time.

If you need the database to do implement thread safety, consider setting the transaction isolation level to SERIALIZED. This should fix the problem at the expense of performance.

 
 

Relacionados problema

7  Cola SPMC sin bloqueo  ( Lock free spmc queue ) 
Aquí está la implementación de la cola de bloqueo para el productor único con un poco de memoria preetratada. T es un tipo simple sin necesidad de operacion...

1  Simple bucle de servidor Java multi-roscado  ( Simple multi threaded java server loop ) 
Soy nuevo en sockets y servidores en general y me gustaría saber si estoy haciendo algo realmente incorrecto en el siguiente bucle de servidor para hilos de d...

3  Cola MultiPhread Generic Simple  ( Simple generic multithreaded queue ) 
Esta es una cola de hilo simple que se usa en un modelo de consumidor productor. public class ThreadedQueue<TType> { private Queue<TType> _queue; p...

5  Biblioteca para realizar pruebas A / B en una aplicación web  ( Library for doing a b tests in a web app ) 
Hice una biblioteca simple para ayudarme a realizar pruebas de A / B en una aplicación web. La idea es simple: tengo dos o más opciones de páginas (URL) para ...

48  Safe-Safe y Lock-Free - Implementación de la cola  ( Thread safe and lock free queue implementation ) 
Estaba tratando de crear una implementación de colas de bloqueo en Java, principalmente para el aprendizaje personal. La cola debe ser general, lo que permite...

6  Paralelizando un algoritmo con OpenMP utilizando una cola de trabajo dinámica  ( Parallelizing an algorithm with openmp using a dynamic work queue ) 
Estoy buscando comentarios sobre el diseño, la corrección y el rendimiento (no tanto estilo) de una cola de trabajo dinámica para las hilos de los trabajadore...

4  BlockingQueue implemetation usando Reentrantlock  ( Blockingqueue implemetation using reentrantlock ) 
Estaba escribiendo mi propia implementación de BlockingQueue para la práctica. Estoy tratando de evitar el uso de la palabra clave sincronizada para los métod...

4  Altere el código de registro centralizado para ser seguro de hilo  ( Alter centralized logging code to be thread safe ) 
Estoy usando este código para recibir mensajes de registro de mis clientes. Recibo más de 1000 conexiones por minuto y quiero aumentar mi manejo de registros,...

5  Caché de objeto Safe-Safe, para lectura, alto rendimiento en .NET  ( Thread safe object cache for read high performance in net ) 
Quiero realizar un caché de objeto que sostiene objetos cargados de la base de datos, el archivo u otra fuente de acceso lento, para que estén disponibles ráp...

1  Aplicación shared_instance usando C ++ y RAII  ( Shared instance implementation using c and raii ) 
He creado un pequeño singleton , como una clase que se elimina cuando ya no hay ninguna referencia a ella (por lo que su vida, será algo predecible). Me apun...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos