使用std :: thread和std :: bind在成员函数中启动线程

时间:2019-10-07 10:17:19

标签: c++ multithreading c++11

我对以下代码快照的查询很少。

1)关于pthread_create(),假设Thread_1创建了Thread_2。据我了解,Thread_1可以不加入而退出,但是Thread_2仍将继续运行。如下面的示例中没有join()的示例,我无法运行线程,并且看到异常。

2)在少数示例中,我看到没有线程对象的线程创建如下。但是当我这样做时,代码就会终止。

std::thread(&Task::executeThread, this);

I am compiling with below command.
g++ filename.cpp -std=c++11 -lpthread

但是它仍然以异常终止。这是创建线程的正确方法还是C ++的任何其他版本(在我的项目中,他们已经在编译但不确定版本)。

3)在我的项目代码的一些示例中,我看到了以下创建线程的方法。但是我无法执行以下示例。

std::thread( std::bind(&Task::executeThread, this) );

下面是我的代码快照。

#include <iostream>
#include <thread>

class Task
{
    public:
    void executeThread(void)
    {
        for(int i = 0; i < 5; i++)
        {
           std::cout << " :: " << i << std::endl;
        }
    }

    void startThread(void);
};

void Task::startThread(void)
{
    std::cout << "\nthis: " << this << std::endl;

#if 1
    std::thread th(&Task::executeThread, this);
    th.join(); // Without this join() or while(1) loop, thread will terminate
    //while(1);
#elif 0
    std::thread(&Task::executeThread, this);  // Thread creation without thread object
#else
    std::thread( std::bind(&Task::executeThread, this) );
    while(1);
#endif
}

int main()
{
    Task* taskPtr = new Task();
    std::cout << "\ntaskPtr: " << taskPtr << std::endl;

    taskPtr->startThread();

    delete taskPtr;
    return 0;
}

感谢与问候

毗湿奴比玛

4 个答案:

答案 0 :(得分:5)

std::thread(&Task::executeThread, this);语句创建并销毁线程对象。当线程未加入或未断开时(例如您的语句中),destructor of std::thread会调用std::terminate

在C ++ 11中没有充分的理由使用std::bind,因为在空间和速度方面,lambda更好。

构建多线程代码时,在编译和链接时都需要指定-pthread选项。链接器选项-lpthread既不合适又不必要。

答案 1 :(得分:4)

根据设计,您需要加入所有产生的线程,或者分离它们。参见例如SO question on join/detach

另请参阅cppreference, detach

请注意重要的警告if main() exits while detached threads are still running

我也100%同意另一个答案中关于首选lambda绑定的评论。

最后,请不要对C ++中的线程执行pthread_cancel的诱惑。参见例如pthread_cancel considered harmful

答案 2 :(得分:1)

  1. 在C ++中,对象具有生存期。这与在C中处理句柄有些不同。在C ++中,如果在一个作用域中的堆栈上创建对象,则退出该作用域将被销毁。这些规则有一些例外,例如std::move,但根据经验,您拥有对象的生命周期。

  2. 这与上述相同。当您调用std::thread(&Task::executeThread, this);时,您实际上是在调用线程构造函数。这是线程寿命和对象寿命的开始。请注意,您在堆栈上创建了此对象。如果您离开范围{ .. yourcode .. },则将调用DTor。由于您是在std::movejoindetatch之前完成此操作的,因此调用std::terminate()会引发异常。

  3. 您可以以这种方式创建线程。如果您查看链接文档的std :: thread :: thread(构造函数),则有一个以相同方式创建对象foo的示例。您收到什么错误?

相关文档:

a。 std::thread::~thread()

b。 std::thread::thread

c。 Lifetime in C++

我个人建议理解C ++中对象的生存期。简而言之,所有对象都在调用其构造函数时开始其生命周期。当它们被杀死(如超出范围)时,将调用其析构函数。编译器会为您处理此问题,因此,如果您来自C,它是一个新概念。

答案 3 :(得分:0)

谢谢大家的投入。我错过了线程对象作为线程创建的一部分。由于进行了编译,因此出现了异常。下面是我的更新代码。这三种情况都可以正常工作。

cc1