据我所知,构造函数/析构函数调用方式的唯一区别取决于实例化顺序。但是“普通”用户类和std中的类之间是否还有其他区别?

假设我有一个名为myStackOverflow的类,然后实例化该类的对象。在同一个作用域中,我还有一个std::thread类型的对象。这些对象的构造函数或析构函数的调用方式是否有所不同?

我问这的主要原因是,根据C++ standard(第30.3.2.3节),在线程析构函数中未调用join()。您可以阅读为什么here。但是在关于堆栈溢出的this答案中,提到将std::thread包装在另一个类中,然后在这个新包装类的析构函数中调用join()。我不知道那将如何解决任何问题。析构函数仍然是析构函数,并且在join()的析构函数中调用std::thread的危险仍然存在。

唯一有意义的方法是这两种不同类型的析构函数的调用方式有所不同。

最佳答案

好的@Ali,让我们简要概述一些事情(术语)。

namespace std-是一个简单的名称空间,例如:

namespace my_namespace {
    int my_integer;
};


其中包含大量有用的程序类,这些类是由超能力的人编写的,并且,如您所知,它应该尽可能灵活(后来的“声明1”),因为不同的人有不同的需求。

当然,它也遵循c ++标准的一般规则,因为它的内容也是如此。



现在让我们谈谈您想要的std::thread

它是一个表示a single thread of execution的简单类。它允许您在“外层空间”中执行功能,并与我们的抽象“外层空间”保持联系,还可以处理一些数据:


_id-线程ID
_handle-秘密变量,是与“外层空间”进行通信的关键
当然,它保留一些数据
关于执行状态(现在是否有任何实体在某处执行
键引导我们到达的“外层空间”


如果您更详细地查找some references并记住我们的“声明1”,您将注意到以下信息:


std::thread对象也可能处于不代表任何线程的状态”
“没有两个std::thread对象可以表示同一执行线程; std::thread不是CopyConstructible或CopyAssignable,尽管它是MoveConstructible和MoveAssignable。




现在您应该得出一个结论,即std::thread变量和执行实体是分开的,但是尝试删除附加到执行实体的std::thread变量会引发异常。

但是当实体完成执行时,std::thread变量将保持活动状态,并且可以附加到任何其他实体。

针对这些需求,有以下几种方法:

 join() // waits for a thread to finish its execution
 // if it is attached to something, the code execution will not go futher until our entity finishes its execution.

 detach() // permits the thread to execute independently from the thread handle
// detaches our std:: thread variable from executing entity, now our entity lives its own life. std::thread variable may be removed while the entity keeps alive

joinable() // checks whether the thread is joinable, i.e. potentially running in parallel context
// if thread is attached to something which is executing now, it returns true, otherwise false




这里有一些代码示例可以清除您的误解:

#include <iostream>
#include <thread>
#include <chrono>

using namespace::std;

void some_func1() {
    cout << "some_func1 thread started " << endl;
    this_thread::sleep_for(chrono::seconds(2));
    cout << "some_func1 thread finished " << endl;
}

void some_func2() {
    cout << "some_func2 thread started " << endl;
    this_thread::sleep_for(chrono::seconds(2));
    cout << "some_func2 thread finished " << endl;
}


int main() {

    thread some_thread;

    cout << "Is some_thread joinable: " << some_thread.joinable() << endl;

    some_thread = thread(some_func1);

    cout << "Is some_thread joinable: " << some_thread.joinable() << endl;

    some_thread.detach();

    cout << "Is some_thread joinable: " << some_thread.joinable() << endl;

    this_thread::sleep_for(chrono::seconds(1));

    some_thread = thread(some_func2);

    cout << "Is some_thread joinable: " << some_thread.joinable() << endl;

    some_thread.join();

    cout << "Is some_thread joinable: " << some_thread.joinable() << endl;
}

//  Output is:
//  Is some_thread joinable: 0
//  some_func1 thread started
//  Is some_thread joinable: 1
//  Is some_thread joinable: 0
//  some_func2 thread started
//  Is some_thread joinable: 1
//  some_func1 thread finished
//  some_func2 thread finished
//  Is some_thread joinable: 0
//  Press any key to continue . . .




如果您希望确保自己的实体在线程变量删除之前完成执行,则可以将其包装在另一个类中,并在析构函数中调用join(),如您所提到的。

或者也可以将其包装在另一个将在析构函数中调用detach()的文件中。

泰斯2种方式将阻止您大量的暗恋。

#include <iostream>
#include <thread>
#include <chrono>

using namespace std;


typedef void Myfunc();

void some_func1() {
    cout << "some_func1 thread started " << endl;
    this_thread::sleep_for(chrono::seconds(2));
    cout << "some_func1 thread finished " << endl;
}

void some_func2() {
    cout << "some_func2 thread started " << endl;
    this_thread::sleep_for(chrono::seconds(2));
    cout << "some_func2 thread finished " << endl;
}

class ICareAboutThread {
    std::thread thread_;
public:
    ICareAboutThread( Myfunc f = nullptr) : thread_(f) {};
    ~ICareAboutThread() { join(); }
    bool joinable() { return thread_.joinable();}
    void join() { thread_.join();}
    void detach() { thread_.detach();}

    // other constructors : move , safe copying - if necessary;
};


class IDontCareAboutThread {
    std::thread thread_;
public:
    IDontCareAboutThread(Myfunc f = nullptr) : thread_(f) {};
    ~IDontCareAboutThread() { detach(); }
    bool joinable() { return thread_.joinable(); }
    void join() { thread_.join(); }
    void detach() { thread_.detach(); }

    // other constructors : move , safe copying - if necessary;
};

int main() {

    ICareAboutThread i_care(some_func1);

    this_thread::sleep_for(chrono::seconds(1));

    IDontCareAboutThread i_dont_care(some_func2);

    return 0;
}

//  Output is:
//  some_func1 thread started
//  some_func2 thread started
//  some_func1 thread finished
//  Press any key to continue . . .




现在,我希望它对您来说非常清晰,如果您了解何时删除变量:D

关于c++ - 用户定义的类和std类之间有区别吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43243447/

10-11 22:39
查看更多