safe - ¿Por qué no hay una cola genérica sincronizada en.NET?
stack<t> (4)
(Supongo que te refieres a Queue <T> para el segundo).
No puedo responder específicamente la pregunta, excepto que las propiedades IsSynchronized y SyncRoot (pero no Synchronize () explícitamente) se heredan de la interfaz de ICollection. Ninguna de las colecciones genéricas usa esto y la interfaz ICollection <T> no incluye SyncRoot.
En cuanto a por qué no está incluido, solo puedo especular que no fueron utilizados en la forma prevista por los diseñadores de la biblioteca o que simplemente no fueron utilizados lo suficiente como para justificar su retención en las colecciones más nuevas.
Me di cuenta de que puede llamar a Queue.Synchronize para obtener un objeto de cola seguro para subprocesos, pero el mismo método no está disponible en Queue <T>. ¿Alguien sabe por qué? Parece un poco raro.
Hay uno ahora, en .Net 4.0:
ConcurrentQueue<T>
en System.Collections.Concurrent
Puede que le interese consultar Parallel CTP; Aquí hay una entrada de blog de los muchachos que la están uniendo, que es bastante actual:
Enumeración de colecciones concurrentes
No es exactamente lo mismo, pero podría resolver su problema más grande. (Incluso usan Queue<T>
versus ConcurrentQueue<T>
como su ejemplo).
Actualización : en .NET 4, ahora existe ConcurrentQueue<T>
en System.Collections.Concurrent, como se documenta aquí http://msdn.microsoft.com/en-us/library/dd267265.aspx . Es interesante observar que su método IsSynchronized (con razón) devuelve false.
ConcurrentQueue<T>
es una reescritura completa, creando copias de la cola para enumerar y utilizando técnicas avanzadas sin bloqueo como Interlocked.CompareExchange()
y Thread.SpinWait()
.
El resto de esta respuesta sigue siendo relevante en la medida en que se relaciona con la desaparición de los antiguos miembros Synchronize () y SyncRoot, y por qué no funcionaron muy bien desde la perspectiva de API.
Según el comentario de Zooba, el equipo de BCL decidió que demasiados desarrolladores estaban malinterpretando el propósito de Synchronize (y, en menor medida, SyncRoot)
Brian Grunkemeyer describió esto en el blog del equipo de BCL hace un par de años: http://blogs.msdn.com/bclteam/archive/2005/03/15/396399.aspx
La cuestión clave es obtener la granularidad correcta alrededor de los bloqueos, donde algunos desarrolladores usan ingenuamente múltiples propiedades o métodos en una colección "sincronizada" y creen que su código es seguro para subprocesos. Brian usa Cola como su ejemplo,
if (queue.Count > 0) {
object obj = null;
try {
obj = queue.Dequeue();
Los desarrolladores no se darían cuenta de que Count podría cambiarse por otro subproceso antes de invocar a Dequeue.
Obligar a los desarrolladores a utilizar una instrucción de bloqueo explícito en toda la operación significa evitar esta falsa sensación de seguridad.
Como Brian menciona, la eliminación de SyncRoot se debió en parte a que se había introducido principalmente para admitir Synchronized, pero también porque en muchos casos hay una mejor opción de objeto de bloqueo: la mayoría de las veces, ya sea la instancia de Queue o una
private static object lockObjForQueueOperations = new object();
en la clase que posee la instancia de la Cola ...
Este último enfoque es generalmente más seguro ya que evita algunas otras trampas comunes:
Como dicen, enhebrar es difícil y hacer que parezca fácil puede ser peligroso.