c++ - una - programacion matrices
Seguridad de subprocesos al escribir una matriz std:: vector vs plain (4)
En este caso, ¿debería simplemente construir su vector con el número necesario de valores? y todo funcionará bien.
std::vector<int> data(n, 0);
resize()
funciona bien para. El rendimiento será igual. La razón por la que el acceso multihilo no dañará el vector es: sus datos se encuentran en su lugar y no se moverán desde allí. Los subprocesos OMP no tendrán acceso al mismo elemento a la vez.
He leído en Stackoverflow que ninguno de los contenedores STL son seguros para la escritura . ¿Pero qué significa eso en la práctica? ¿Significa que debo almacenar datos grabables en matrices simples?
Espero que las llamadas simultáneas a std::vector::push_back(element)
puedan conducir a estructuras de datos inconsistentes, ya que podría implicar cambiar el tamaño del vector. Pero ¿qué pasa con un caso como este, donde el cambio de tamaño no está involucrado:
1) usando una matriz:
int data[n];
// initialize values here...
#pragma omp parallel for
for (int i = 0; i < n; ++i) {
data[i] += func(i);
}
2) usando un `std :: vector``:
std::vector<int> data;
data.resize(n);
// initialize values here...
#pragma omp parallel for
for (int i = 0; i < n; ++i) {
data[i] += func(i);
}
¿Es la primera implementación realmente mejor que la segunda a) en términos de seguridad de subprocesos yb) en términos de rendimiento? Preferiría usar un std :: vector, ya que me siento menos cómodo con los arreglos de estilo C.
EDITAR: #pragma omp atomic update
una #pragma omp atomic update
protege la escritura.
Lo principal que significa es que si tiene varios subprocesos que acceden al vector, no puede depender de C ++ para evitar que corrompa la estructura de datos con varias escrituras simultáneas. Así que necesitas usar algún tipo de guardia. Por otro lado, si su programa no utiliza múltiples subprocesos, como sus ejemplos no parecen, está perfectamente bien.
Los dos son igualmente seguros. Siempre que no se acceda a ningún elemento desde varios subprocesos, está bien. Su bucle paralelo accederá a cada elemento solo una vez, y por lo tanto solo desde un hilo.
Hay espacio en el estándar para que las funciones miembro de los contenedores no sean seguras para subprocesos. En este caso, usa vector<int>::operator[]
, por lo que querría una garantía explícita de seguridad de subprocesos para ese miembro, lo que parece razonable ya que llamarlo incluso en un vector no constante no modifica el vector sí mismo. Entonces, dudo que haya un problema en este caso, pero no he buscado la garantía [edit: rici found]. Incluso si es potencialmente inseguro, podría hacer int *dataptr = &data.front()
antes del bucle y luego indexar dataptr
lugar de data
.
Además, no se garantiza que este código sea seguro para vector<bool>
, ya que es un caso especial en el que coexisten múltiples elementos dentro de un objeto. Sería seguro para una matriz de bool
, ya que los diferentes elementos de eso son diferentes "ubicaciones de memoria" (1.7 en C ++ 11).
Para c ++ 11, que especifica reglas para las carreras de datos, se describe la seguridad de subprocesos de los contenedores. Una sección relevante de la norma es el § 23.2.2, párrafo 2:
No obstante (17.6.5.9), se requieren implementaciones para evitar las carreras de datos cuando los contenidos del objeto contenido en diferentes elementos en la misma secuencia, excepto el vector <bool>, se modifican al mismo tiempo.
[Nota: para un vector <int> x con un tamaño mayor que uno, x [1] = 5 y * x.begin () = 10 se pueden ejecutar simultáneamente sin una carrera de datos, pero x [0] = 5 y * x.begin () = 10 ejecutado simultáneamente puede resultar en una carrera de datos. Como excepción a la regla general, para un vector <bool> y, y [0] = verdadero puede correr con y [1] = verdadero. "Nota final"
El § 17.6.5.9 mencionado esencialmente prohíbe cualquier modificación concurrente por cualquier interfaz de biblioteca estándar a menos que esté específicamente permitido, por lo que la sección que cito le dice exactamente qué está permitido (y eso incluye su uso).
Como Steve Jessop planteó la pregunta, el párrafo 1 del § 23.2.2 permite explícitamente el uso concurrente de []
en contenedores de secuencia:
Para evitar las carreras de datos (17.6.5.9), las implementaciones deben considerar las siguientes funciones const: begin, end, rbegin, rend, front, back, data, find, lower_bound, upper_bound, equal_range, at y, excepto en asociativo o contenedores asociativos desordenados, operador [].