Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

382
Vistas
Al generar, se encuentra que currentId no es 10000 como se esperaba. ¿Por qué? como corregirlo

Este código lo vi por casualidad. El código es más o menos como sigue.

 public class Question2 { public void Run() { List<Task> tasks = new List<Task>(); for (int i = 0; i < 10000; i++) { tasks.Add(Task.Factory.StartNew(() => { GetNextId(); })); } Task.WaitAll(tasks.ToArray()); Console.WriteLine("currentId=" + GetCurrentId()); Console.ReadKey(); } private int currentId; public int GetNextId() { currentId++; return currentId; } public int GetCurrentId() { return currentId; } }

No sé por qué el resultado no es 10000. Alguien me puede decir porque y como corregirlo.

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

¡Acabas de descubrir el tema de la seguridad de subprocesos! currentId++ traduce como

  1. leer el valor de currentId de la memoria
  2. incrementar este valor en uno
  3. escribe este nuevo valor en la memoria

Ahora imagine que su ciclo va solo hasta i < 3. El primer hilo está en el paso 1 y lee el valor 0. Antes de pasar al paso 2, el segundo hilo está en el paso 1 y también lee 0. Ahora ambos hilos van al paso 3, escribirá ambos 1 en la memoria. Ahora comienza el tercer hilo y leerá 1 de la memoria, lo incrementará a 2 y lo escribirá en la memoria. Ahora tiene 2 en lugar del valor esperado 3.

Para solucionar esto, puede usar Interlocked.Increment :

 private int currentId; public int GetNextId() { return Interlocked.Increment(ref currentId); }

Pero tenga en cuenta que, dependiendo de su caso de uso, es posible que aún tenga problemas similares cuando use el valor de retorno de GetNextId() .

over 4 years ago · Santiago Trujillo Denunciar

0

currentId++;

En un programa de un solo subproceso, la secuencia de eventos se ve así.

  1. El subproceso lee el valor de currentId (por ejemplo, 999).
  2. El subproceso incrementa el valor y escribe en currentId. El valor de currentId ahora es 1000.

En su programa de subprocesos múltiples, la secuencia de eventos puede parecerse más a esto.

  1. El subproceso 1 lee el valor de currentId (por ejemplo, 999).
  2. El subproceso 2 lee el valor de currentId (también, 999).
  3. El subproceso 3 lee el valor de currentId (también, 999).
  4. El subproceso 2 incrementa el valor y escribe en currentId. El valor de currentId ahora es 1000.
  5. Thread 3 incrementa el valor y escribe en currentId. El valor de currentId ahora es 1000.
  6. El subproceso 1 incrementa el valor y escribe en currentId. El valor de currentId ahora es 1000.

Entonces, el valor de currentId se incrementó tres veces, pero el valor es 1000.

Una solución a este problema es usar la palabra clave lock. El uso de la palabra clave lock garantiza que solo un subproceso tenga acceso a un fragmento de código a la vez.

 private int currentId; private object _object = new object(); public int GetNextId() { lock (_object) { currentId++; return currentId; } }

La secuencia de eventos ahora se ve así.

  1. El subproceso 1 obtiene acceso a la cerradura (_objeto).
  2. El subproceso 1 lee el valor de currentId (por ejemplo, 999).
  3. El subproceso 2 solicita acceso al bloqueo (_objeto) pero se ve obligado a esperar hasta que el subproceso 1 libere el bloqueo.
  4. El subproceso 3 solicita acceso a la cerradura (_objeto). La solicitud se pone en cola detrás de la solicitud del subproceso 2.
  5. El subproceso 1 incrementa el valor y escribe en currentId. El valor de currentId ahora es 1000.
  6. El subproceso 1 libera el bloqueo (_objeto).
  7. El subproceso 2 obtiene acceso a la cerradura (_objeto).
  8. El subproceso 2 lee el valor de currentId (ahora, 1000).
  9. El subproceso 2 incrementa el valor y escribe en currentId. El valor de currentId ahora es 1001.
  10. El subproceso 2 libera el bloqueo (_objeto).
  11. El subproceso 3 obtiene acceso a la cerradura (_objeto).
  12. El subproceso 3 lee el valor de currentId (ahora, 1001).
  13. Thread 3 incrementa el valor y escribe en currentId. El valor de currentId ahora es 1002.
  14. El subproceso 3 libera el bloqueo (_objeto).

Tenga en cuenta que el resultado seguirá siendo 9999 si el valor inicial es cero y lo incrementa 9999 veces.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda