es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Estás teniendo un problema extraño al capturar una referencia o copia de un puntero compartido en un hilo?

Solo mira la demostración que escribí a continuación:

#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <unistd.h>

using namespace std;

class SomethingWithVec
{
public:
    SomethingWithVec() {}
    void push(int num)
    {
        lock_guard<mutex> guard(mutex);
        v.push_back(num);
    }
    int size()
    {
        lock_guard<mutex> guard(mutex);
        return v.size();
    }

private:
    vector<int> v;
    mutex mutex;
};

int main(int argc, char **argv)
{
    vector<thread> threads;
    vector<><somethingwithvec>> vecs;
    for (int i = 0; i < 4; i++)
    {
        auto sth = make_shared<somethingwithvec>();
        threads.emplace_back([&sth]
                             {
                                 while (true)
                                 {
                                     this_thread::sleep_for(2000ms);
                                     printf("size at thread[%d] is %d\n", gettid(), sth->size());
                                 }
                             });
        vecs.push_back(sth);
    }
    vecs[1]->push(1);
    for (int i = 0; i < 4; i++)
        threads[i].join();
    return 0;
}

Creo una clase SomethingWithVec que admite lectura/escritura concurrente usando mutex. Y en la función principal, creo 4 hilos capturando la referencia de un puntero compartido correspondiente de SomethingWithVec. Luego modifico uno de los SomethingWithVec externamente. Espero ver que uno de los hilos imprime “size = 1”, pero obtengo la siguiente salida:
size at thread[30819] is 0
size at thread[30822] is 0
size at thread[30821] is 0
size at thread[30820] is 0

Parece que no sucedió nada después de agregar un valor a vecs[1].

Luché con esto durante bastante tiempo, pero una vez que cambio [&sth] a [sth], la salida parece estar perfectamente correcta:
size at thread[31595] is 0
size at thread[31597] is 0
size at thread[31598] is 0
size at thread[31596] is 1

Simplemente no puedo entender por qué. Esto es realmente extraño, ¿me estoy perdiendo algo fundamental?</unistd.h>

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El problema aquí está en el uso de [&sth] en la expresión lambda pasada a la función emplace_back. Al capturar sth por referencia, estamos creando una posible condición de carrera entre el hilo principal y los hilos de la función lambda.

    Cuando se ejecuta la función lambda, puede acceder a sth mientras está siendo modificada por el hilo principal. Esto puede llevar a un comportamiento indefinido, que en nuestro caso es la salida inesperada.

    Para solucionar este problema, podemos capturar sth por valor usando [sth]. Al hacer esto, cada función lambda tendrá su propia copia del puntero compartido y cualquier modificación a sth en el hilo principal no afectará a las funciones lambda.

    En resumen, al usar punteros compartidos en un entorno multiproceso, es importante asegurarse de que se accedan de manera segura en hilos. Capturar punteros compartidos por valor en funciones lambda es una forma de lograr esto.

Comments are closed.