主线程是否允许在进入main()之前产生一个POSIX线程? [英] Is the main thread allowed to spawn a POSIX thread before it enters main()?

查看:173
本文介绍了主线程是否允许在进入main()之前产生一个POSIX线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个对象包含一个线程。我想要的对象的命运和线程的命运是一个在同一个。因此,构造函数创建一个线程(使用 pthread_create ),析构函数执行操作以使线程在合理的时间内返回,然后加入线程。这是工作正常,只要我不实例化这些对象与静态存储持续时间。如果我在全局或命名空间或静态类范围实例化这些对象之一,程序编译精细(gcc 4.8.1),但在运行时立即segfaults。使用打印语句我已经确定主线程甚至没有进入main()之前的segfault。任何想法?

I have this object that contains a thread. I want the fate of the object and the fate of the thread to be one in the same. So the constructor creates a thread (with pthread_create) and the destructor performs actions to cause the thread to return in a reasonable amount of time and then joins the thread. This is working fine as long as I don't instantiate one of these objects with static storage duration. If I instantiate one of these objects at global or namespace or static class scope the program compiles fine (gcc 4.8.1) but immediately segfaults upon running. With print statements I have determined that the main thread doesn't even enter main() before the segfault. Any ideas?

更新:还向构造函数的第一行添加了打印语句(因此在 pthread_create 之前调用),甚至没有在segfault之前打印,但构造函数使用初始化列表,所以它是可能的东西导致它?

Update: Also added a print statement to the first line of the constructor (so before pthread_create is called), and not even that gets printed before the segfault BUT the constructor does use an initialization list so it is possible something there is causing it?

这里是构造函数:

worker::worker(size_t buffer_size):
m_head(nullptr),m_tail(nullptr),
m_buffer_A(operator new(buffer_size)),
m_buffer_B(operator new(buffer_size)),
m_next(m_buffer_A),
m_buffer_size(buffer_size),
m_pause_gate(true),
m_worker_thread([this]()->void{ thread_func(); }),
m_running(true)
{
    print("this wont get printed b4 segfault");
    scoped_lock lock(worker_lock);
    m_worker_thread.start();
    all_workers.push_back(this);
}

而析构函数:

worker::~worker()
{
    {
        scoped_lock lock(worker_lock);
        auto w=all_workers.begin();
        while(w!=all_workers.end())
        {
            if(*w==this)
            {
                break;
            }
            ++w;
        }
        all_workers.erase(w);
    }

    {
        scoped_lock lock(m_lock);
        m_running=false;
    }

    m_sem.release();
    m_pause_gate.open();

    m_worker_thread.join();

    operator delete(m_buffer_A);
    operator delete(m_buffer_B);
}

更新2:

好吧,我想出来了。我的打印函数是原子的,同样保护 cout 与extern命名空间作用域互斥定义在别处。我改为只是简单 cout ,它打印在ctor的开头。显然,在尝试访问这些静态存储持续时间互斥体之前,没有一个被初始化。所以是的,这可能是凯西的回答。

Okay I figured it out. My print function is atomic and likewise protects cout with an extern namespace scope mutex defined elsewhere. I changed to just plain cout and it printed at the beginning of the ctor. Apparently none of these static storage duration mutexes are getting initialized before things are trying to access them. So yeah it is probably Casey's answer.

我只是不打扰复杂的对象和静态存储持续时间。

I'm just not going to bother with complex objects and static storage duration. It's no big deal anyway.

推荐答案

非局部变量的初始化在C ++ 11§3.6.2中有描述,第2段中与线程有关的许多可怕的东西:

Initialization of non-local variables is described in C++11 §3.6.2, there's a ton of scary stuff in paragraph 2 that has to do with threads:


如果程序启动一个线程(30.3)对于在不同的翻译单元中定义的变量的初始化是不确定的。否则,相对于在不同的翻译单元中定义的变量的初始化,变量的初始化不确定地排序。如果一个程序启动一个线程,则对于每个其他动态初始化,一个变量的后续无序初始化是无效的。

If a program starts a thread (30.3), the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit. If a program starts a thread, the subsequent unordered initialization of a variable is unsequenced with respect to every other dynamic initialization.

变量的随后的无序初始化对于每个其它动态初始化是不被排序的意味着所产生的线程不能访问在线程被产生而没有引起数据竞争之前没有被初始化的动态初始化的任何变量。如果该线程不能以 main 同步,你基本上通过雷区跳舞,双手在你的眼睛。

I interpret "the subsequent unordered initialization of a variable is unsequenced with respect to every other dynamic initialization" to mean that the spawned thread cannot access any variable with dynamic initialization that was not initialized before the thread was spawned without causing a data race. If that thread doesn't somehow synchronize with main, you're basically dancing through a minefield with your hands over your eyes.

我强烈建议您阅读并理解所有3.6;即使没有线程,它也是一个巨大的PITA在 main 开始之前做的很多。

I'd strongly suggest you read through and understand all of 3.6; even without threads it's a huge PITA to do much before main starts.

这篇关于主线程是否允许在进入main()之前产生一个POSIX线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆