【问题标题】:Passing object by reference and Multithreading通过引用和多线程传递对象
【发布时间】:2017-06-28 04:00:16
【问题描述】:

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

问题:

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

代码:

#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

【问题讨论】:

  • 你需要联锁增量

标签: c++ multithreading pass-by-reference


【解决方案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

看到它Live

尽管走得更远,你也应该考虑数据竞赛

【讨论】:

  • 您需要atomic_int 或其他方式进行同步。
  • 我很好奇,我不知道 C++ 中存在未定义行为的无限循环,编写这样一个循环的“正确”方法是什么?
  • @juanchopanza 你是对的。尽管对于 OP 的 specific 示例,我认为没有必要深入讨论。增加了担忧。谢谢
  • @ShadowMitia,假定 C++ 中的正确程序会终止,因此编写循环或任何循环的正确方法是始终测试有朝一日会退出循环的条件。请看thisSO线程的答案
  • @WhiZTiM 这是一个很好的例子,谢谢!为了完整起见,您介意在类中添加一个互斥锁吗?线程应该获取锁,然后递增计数器,然后释放它。
【解决方案2】:

我对多线程不是很熟悉,但是您将 b 通过值传递给线程,而不是通过引用。然后b 的值通过引用传递给thread_task,因此该值始终为1。

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

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

【讨论】:

  • 感谢您的解释。
【解决方案3】:

请注意,在std::thread t1(thread_task, b) 中,您将b 按值传递给std::thread 的构造函数(因为您在这里调用构造函数,而不是直接调用thread_task)。一个解决方案可能是将b 包装为std::ref-object,或者更改您的代码以传递一个指针:

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;
}

【讨论】:

    猜你喜欢
    • 2017-09-11
    • 2012-10-04
    • 1970-01-01
    • 2013-12-19
    • 2011-07-06
    • 2012-07-07
    • 2012-01-05
    • 2012-07-16
    相关资源
    最近更新 更多