简体   繁体   English

构造函数中的 pthread_create 段错误

[英]pthread_create in constructor segfault

I discovered, in this little example below, if I call pthread_create in the constructor of my struct, I get a segfault randomly on the call to pthread_mutex_lock().我发现,在下面的这个小例子中,如果我在我的结构的构造函数中调用 pthread_create,我会在调用 pthread_mutex_lock() 时随机得到一个段错误。

And sometimes the name field is empty for the first philosopher.有时,第一位哲学家的姓名字段为空。

If I move pthread_create to a run() function after the constructor, no segfault.如果我在构造函数之后将 pthread_create 移动到 run() function,则没有段错误。

It seems the call to pthread_create happens before all the members are initialized.似乎对 pthread_create 的调用发生在所有成员初始化之前。 Shouldn't the member init list of the class be completed before the call to constructor body? class 的成员初始化列表不应该在调用构造函数体之前完成吗?

Thanks for any tips!感谢您的任何提示!

clang version 9.0.0 (tags/RELEASE_900/final) Target: x86_64-apple-darwin17.7.0 clang 版本 9.0.0 (tags/RELEASE_900/final) 目标:x86_64-apple-darwin17.7.0

Sincerely, George真诚的,乔治

#include <array>
#include <iostream>
#include <pthread.h>
#include <string>
#include <vector>

using namespace std;


struct chopstick
{
        pthread_mutex_t mutex;
        chopstick()
        {
                pthread_mutex_init(&mutex,nullptr);
        }
        ~chopstick()
        {
                pthread_mutex_destroy(&mutex);
        }

};

void* feed(void* data);
struct philosopher
{
        pthread_t thread;
        string name;
        unsigned mouthfuls;
        chrono::seconds sec;
        chopstick &left, &right;

        pthread_t& get_thread() { return thread; }

        philosopher(const string &s, chopstick &l, chopstick &r): name(move(s)), left(l), right(r), mouthfuls(0)
        /*
                enable below to avoid segfault
        {}
        void run()  
        */
        {
                pthread_create(&thread, nullptr, feed, this);
        };

};

void* feed(void* data)
{
        philosopher & a = *static_cast<philosopher*>(data);
        while (a.mouthfuls < 20)
        {
                pthread_mutex_lock(&a.left.mutex);
                pthread_mutex_lock(&a.right.mutex);
                cout << "Apostle " << a.name << " thread id " << pthread_self() 
                        << " acquired a chopstick at count: " << a.mouthfuls << endl;
                ++a.mouthfuls;
                pthread_mutex_unlock(&a.right.mutex);
                pthread_mutex_unlock(&a.left.mutex);
        }
        return nullptr;
}

int main (int argc, char const * argv[])
{
        array<string, 12> names {"John", "Thaddeus", "Simon Peter", "James", "Judhas", "Bartholomew", "Matthew", "Philip", "Simon Zealot", "Thomas", "Andrew", "James the Lesser" };
        array<chopstick,names.size()> sticks;
        vector<philosopher> philosophers;

        for (int i=0; i+1<names.size(); ++i)
                philosophers.emplace_back( names[i],sticks[i],sticks[i+1] );
        philosophers.emplace_back(names[names.size()-1], sticks[0],sticks[names.size()-1]);
        //for (philosopher&  a: philosophers) a.run();  //<-- enable to avoid segfault
        for (philosopher&  a: philosophers) pthread_join(a.get_thread(), nullptr);

        return 0;

}

std::vector resizes when the code does philosophers.emplace_back() , which can move the elements in memory, so that their previous addresses become invalid and the feed() function ends up accessing objects using their old invalid addresses. std::vector在代码执行philosophers.emplace_back()时调整大小,这可以移动 memory 中的元素,从而使它们以前的地址变得无效,并且feed() function 最终使用其旧的无效地址访问对象。

A fix would be to make the philosopher class non-copyable and non-movable, and then use std::list<philosopher> or std::forward_list<philosopher> instead of std::vector<philosopher> .解决方法是使philosopher class 不可复制和不可移动,然后使用std::list<philosopher>std::forward_list<philosopher>代替std::vector<philosopher> std::list and std::forward_list do not move elements in memory and hence are capable of storing non-copyable and non-moveable objects. std::liststd::forward_list不会移动 memory 中的元素,因此能够存储不可复制和不可移动的对象。

You may also like to use std::thread instead of pthread_t , and std::mutex instead of pthread_mutex_t .您可能还想使用std::thread代替pthread_tstd::mutex代替pthread_mutex_t The std classes are non-copyable/movable which would prevent you from making this error at compile-time. std类是不可复制/可移动的,这将防止您在编译时出现此错误。 Also, the code doesn't check return values of the pthread functions for errors, whereas std::thread and std::mutex do that for you.此外,代码不会检查 pthread 函数的返回值是否有错误,而std::threadstd::mutex会为您执行此操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM