通过指针将堆栈分配的对象传递给在另一个线程上执行的函数

Posted

技术标签:

【中文标题】通过指针将堆栈分配的对象传递给在另一个线程上执行的函数【英文标题】:Passing stack allocated objects by pointer to a function which executes on another thread 【发布时间】:2016-08-15 17:36:43 【问题描述】:

据我所知,线程共享堆内存但有自己的堆栈。 因此,如果我通过指针(出于多态原因)将堆栈分配的对象传递给在另一个线程上执行的函数,这将是安全的,还是会得到未定义的行为。例如这段代码:

struct Foo
    int counter0;


void bar(Foo * obj)
    obj->counter++;

int main()
   
        Foo foo_object;
        std::thread t(bar, &foo_object);
        t.detach();
    
    //do more stuff

这是不安全的,因为foo_object 超出范围后,指向foo_object 的指针将无效,但线程可以访问无效内存? 我有一种强烈的感觉,这会产生不确定的行为,但我不是 100% 确定。

【问题讨论】:

不能百分百确定的原因是什么? “安全”是指“正确”吗? 是的,我的意思是正确的安全,如果不清楚,我很抱歉 【参考方案1】:

不,这不安全。一旦你到达 in


    Foo foo_object();
    std::thread t(bar, &foo_object);
    t.detach();

foo_object 将超出范围,您将在分离的线程中留下一个悬空指针。由于我们不知道线程何时实际启动,因此基于堆栈的本地对象在您使用它时已经被销毁是完全合理的。


还要注意Foo foo_object(); 是一个函数声明,而不是一个局部变量。要拥有变量,您需要Foo foo_object;

【讨论】:

【参考方案2】:

当前代码是不安全的,因为 Foo 将在您访问它时被销毁。

如果你有 C++17,我建议你写:

std::thread t([foo_object = Foo] bar(&foo_object); );

虽然您只有 c++11,但我会考虑编写以下内容:

auto foo_object = std::make_shared<Foo>();
std::thread t([foo_object] bar(foo_object.get()); );

它可能会误用 shared_ptr,尽管它主要是有效的。 另一种选择是编写以下内容:

std::thread t([] Foo foo_object; bar(&foo_object); );

【讨论】:

C++17 特性有什么作用?它会在新线程堆栈上创建一个名为 foo_object 的新对象吗? 它将在 Lambda 对象中创建它。【参考方案3】:

foo_object 将在其作用域的末尾被销毁,因此将指针传递给不同的线程是不安全的。如果在 foo_object 被销毁后,单独的线程试图取消对悬空指针的引用,它将调用未定义的行为。

【讨论】:

以上是关于通过指针将堆栈分配的对象传递给在另一个线程上执行的函数的主要内容,如果未能解决你的问题,请参考以下文章

C ++将多个对象传递给线程中的函数

将 QObject 指针从 QML 对象传递给 C++

如何将多个重复的参数传递给 CUDA 内核

C ++将抽象类型的动态分配对象传递给函数并存储在向量中[重复]

如果已知 void* 分配大小,如何将确切的内存大小传递给 free()

如何将 std::function 对象传递给采用函数指针的函数?