对象在多线程中的行为

Behaviour of object in multithread

本文关键字:多线程 对象      更新时间:2023-10-16

我试图使用boost::thread_group来管理我的线程。该设计使得线程组中的每个线程调用结构体A的一个函子序列。

伪代码:

struct A {
    int n;
    vector p;
    void operator()() {
        for(number_of_steps) // Do computations involving members n, p, x and y.
    }
private:
    float x;
    vector y;
};
struct parallel_A : boost::thread_group {
    parallel_A(const A* a) : m_a(a) {
        for(number_of_cpu) {
            create_thread(inner_struct(this));
        }
    }
    void run() {
        (*m_a)();
    }
private:
    struct inner_struct {
        parallel_A* a;
        inner_struct(parallel_A* _a) : a(_a) {}
        void operator()() {
            a->run(); 
        }
    }
    const A* m_a;
}

我的问题是

  1. 数据变量npxy与对象A中的计算是否会被线程交错 ?

  2. 如果我们更进一步,对每个CPU有更多的A函数调用,例如1个线程对应1个CPU,每个线程对A函数调用4次来进行计算,那么A的变量状态和计算将会有什么行为?

  1. 基于代码:

    for(number_of_cpu) {
        create_thread(inner_struct(this));
    

    相同的this指针值将传递给所有线程,因此线程将共享相同的n, p, xy数据变量。A的计算在任何情况下都会交错(除了临界区),但现在由于计算共享相同的数据变量,因此很有可能一次计算将使用用于另一次计算的中间值,从而导致数据损坏。

    我建议在这里使用某种形式的线程本地存储,通过定义A对象数组和/或使用正式机制,如boost::thread_specific_ptr。

  2. 如果不使用线程本地存储(即维持上面的代码),增加A函数的调用将增加数据损坏的机会。

    如果使用线程本地存储,由于指令仍然在线程内顺序执行,在每个线程中增加4个A函数调用将意味着计算时间大约是原来的5倍。这假定在每个线程中没有创建子线程来处理额外的调用。