通过引用和多线程传递对象

Passing object by reference and Multithreading

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

我有一个小问题,想知道是否有人可以提供帮助。我试图以最简单的方式展示我的问题。我正在尝试通过引用多个线程来传递一个对象。每个线程都调用"doSomething",这是一个属于对象"示例"的成员函数。"doSomething"函数应该增加计数器。我的 gcc 版本是 4.4.7

问题:

为什么变量"计数器"的值没有递增,尽管我通过引用线程函数传递了对象。

代码:

#include <iostream>
#include <thread>
class Exmaple {
    private:
        int counter;
    public:
            Exmaple() { 
            counter = 0;
        }    
        void doSomthing(){
            counter++;
        }
        void print() {
            std::cout << "value from A: " << counter << std::endl;
        }
};
// notice that the object is passed by reference
void thread_task(Exmaple& o) {
    o.doSomthing();
    o.print();
}    
int main()
{
    Exmaple b;
    while (true) {
        std::thread t1(thread_task, b);
        t1.join();
    }    
    return 0;
}

输出:

value from A: 1
value from A: 1
value from A: 1
value from A: 1
value from A: 1
value from A: 1
value from A: 1
value from A: 1
value from A: 1
while (true) {
    std::thread t1(thread_task, b);
    t1.join();
}  

您需要了解的两件事:

  • 使用 std::ref 传递引用。
  • 无限循环是C++中未定义的行为;

工作示例如下:

#include <iostream>
#include <thread>
class Exmaple {
    private:
        int counter;
    public:
            Exmaple() { 
            counter = 0;
        }    
        void doSomthing(){
            counter++;
        }
        void print() {
            std::cout << "value from A: " << counter << std::endl;
        }
};
// notice that the object is passed by reference
void thread_task(Exmaple& o) {
    o.doSomthing();
    o.print();
}    
int main()
{
    Exmaple b;
    for(int i =0; i < 10; i++) {
        std::thread t1(thread_task, std::ref(b));
        t1.join();
    }    
    return 0;
}

输出:

value from A: 1
value from A: 2
value from A: 3
value from A: 4
value from A: 5
value from A: 6
value from A: 7
value from A: 8
value from A: 9
value from A: 10

现场观看。

虽然走得更远,但你还应该考虑数据竞争

我对多线程不是很熟悉,但是您是通过值而不是通过引用将b传递给线程的。然后b的值通过引用传递给thread_task,所以这个值总是1。

根据文档,您必须像这样编写线程才能通过引用传递对象:

std::thread t1(thread_task, std::ref(b));

请注意,在std::thread t1(thread_task, b)中,您将 b 按值传递给 std::thread 的构造函数(您在此处调用构造函数,而不是直接thread_task(。解决方案可能是通过std::ref对象包装b,或者更改代码以传递指针:

void thread_task(Exmaple* o) {
    o->doSomthing();
    o->print();
}
int main()
{
    Exmaple b;
    while (true) {
        std::thread t1(thread_task, &b);
        t1.join();
    }
    return 0;
}