在c++ (cpp)中,在类中创建一个线程并让它在类中的函数上执行

making a thread within a class and having it execute on a funtion within the class in c++ (cpp)

本文关键字:执行 函数 cpp c++ 创建 一个 线程      更新时间:2023-10-16

我想做一个程序,其中有多个线程,线程之间的唯一交互应该是创建几个变量,仅用于在线程之间传输。其中一个是队列。我想让一个线程不断地写文件,我想让其他线程不断地给它写行。

但是为了简单起见,我想通过创建类然后简单地从该类调用一个名为give_line()的函数来实现这一切。我想要的线程是写的文件私有,这样别人就不能乱搞它。

class bar
{
private:
    std::queue<std::string> lines;    // The queue
    void write()                      // The function we call from thread
    {
        std::cout << "Hello world from other thread";
    }
public:
    bar()                             // constructor
    {
        std::thread writer(&bar::write, this);     // thread
    }
}
int main()
{
    bar testing;
    std::cout << "Hello World from main thread" << std::endl;
    /*
    What this does is it allows me to keep the console open till we get a enter key.
    */
    std::cin.clear();
    std::cin.ignore(32767, 'n');
    std::cin.get();

    return 0;
}

.

output:
    Hello world from other thread 

为什么这没有意义,为什么它不起作用,我不明白。它启动了,然后突然崩溃了。我想不明白。当我在一个类中没有它时,它就会起作用,但是其他人可以扰乱线程,我真的不想这样。除非我需要,否则我不会给出太多项目代码。我创建这个类以及其他函数和变量的原因是你们不需要知道的。

我知道我需要一个writer.join()。但那是以后的事了。我想要另一个变量能够一次结束一切。这个变量只能从主线程访问,所以其他线程不能干扰它。有点像kill_all变量。

这里有多个问题,但首先也是最重要的是std::thread的构造函数在新启动的线程中执行函数。看起来你不是在传递一个函数,而是在传递一个类方法。

我相当确定,当你的编译器试图编译这段代码时,它对你大喊大叫。仅仅因为你的编译器选择生成某种编译的目标文件,尽管它报告了错误,并不意味着编译器的诊断可以被忽略。

你可能想做这样的事情:

static void invoke_write(bar *p)
{
     p->write();
}
bar()
{
     std::thread writer(&invoke_write, this); 
}

现在,您正在调用一个静态函数,并向它传递一个指向实例化类的指针,它使用该指针调用类方法。

但是你崩溃的真正原因是因为你在bar的构造函数范围内实例化了std::thread的实例。

bar的构造函数返回时,std::thread对象,就像任何其他函数/方法作用域对象一样,被销毁,调用它的析构函数。但是,您刚刚启动了正在运行的线程,如果在线程仍在运行时调用std::thread的析构函数,则会调用terminate(),从而终止程序。

如果线程正在运行,必须在销毁std::thread实例之前执行join()。所以,要么像这样:

bar()
{
     std::thread writer(&invoke_write, this); 
     writer.join();
}

或者,使std::thread的实例成为类成员,在构造函数中实例化它,并在析构函数中加入它。比如:

    bar() : writer(&invoke_write, this)
    {
    }
    ~bar()
    {
         writer.join();
    }
private:
    std::thread writer;

当然,哪种方法是正确的取决于您的应用程序的需求。

对您的类进行一个简单的更改,与@Sam Varchavchik一致,是为了确保在创建线程对象后不会立即丢失线程对象。

class bar
{
private:
    std::queue<std::string> lines;    // The queue
    std::thread writer;
    void write()                      // The function we call from thread
    {
        std::cout << "Hello world from other thread";
    }
public:
    bar() : writer{&bar::write, this} {}
    ~bar()
    {
        writer.join();
    }
};

这里,写线程在构造函数中初始化,在析构函数中等待它完成。

您可以在这里看到稍微修改过的代码运行:http://ideone.com/Xf4dw5

正如Sam所提到的,在旧的c++中,不能仅仅通过传递类方法来创建线程,因为它也需要有对象。现代c++通过将两者绑定在一起来实现这一点,就像你通过将'this'传递给线程构造函数所做的那样。