我有这个包含线程的对象。我希望对象的命运和线程的命运是同一个。因此构造函数创建一个线程(带有pthread_create
),析构函数执行操作以使线程在合理的时间内返回,然后加入线程。只要我没有使用静态存储持续时间实例化其中一个对象,这样就可以正常工作。如果我在全局或命名空间或静态类范围中实例化其中一个对象,程序编译正常(gcc 4.8.1)但在运行时立即进行段错误。使用print语句,我确定主线程甚至在segfault之前都没有进入main()。有什么想法吗?
更新:还在构造函数的第一行添加了一个print语句(所以在调用pthread_create
之前),甚至在segfault之前都没有打印但是构造函数确实使用了初始化列表,因此它是可能的有什么东西导致它?
这是构造函数:
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:
好吧我明白了。我的print函数是原子的,同样用其他地方定义的extern命名空间作用域mutex来保护cout
。我改为普通cout
,并在ctor的开头打印。显然,在尝试访问它们之前,这些静态存储持续时间互斥体都没有被初始化。所以是的,这可能是凯西的答案。
我只是不打扰复杂的对象和静态存储持续时间。无论如何,这没什么大不了的。
答案 0 :(得分:6)
非局部变量的初始化在C ++11§3.6.2中有描述,第2段中有很多与线程有关的可怕内容:
如果程序启动一个线程(30.3),则对于在不同转换单元中定义的变量的初始化,后续的变量初始化是未排序的。否则,对于在不同转换单元中定义的变量的初始化,变量的初始化是不确定地排序的。如果程序启动一个线程,则对于每个其他动态初始化,后续无序的变量初始化都是无序的。
我解释“后续的无序初始化变量对于其他所有动态初始化都没有排序”意味着生成的线程无法访问任何变量,动态初始化在线程生成之前未初始化而不会导致数据竞争。如果那个线程没有以某种方式与main
同步,你基本上是用手捂着眼睛在雷区跳舞。
我强烈建议你仔细阅读并理解3.6;即使没有线程,在main
开始之前,它也是一个巨大的PITA。
答案 1 :(得分:0)
在进入main之前会发生什么事情是特定于平台的,但这里有一个关于main()在Linux上执行的链接
http://linuxgazette.net/84/hawk.html
有用的snipet是
__ libc_start_main初始化必要的东西,特别是C库(如malloc)和线程环境,并调用我们的主。
有关更多信息,请查看__libc_start_main
不确定这在Windows上是如何表现的,但在进入main之前似乎任何标准C库调用都不是一个好主意
答案 2 :(得分:0)
可能有很多方法可以做到这一点。请参阅下面的代码段,其中A类的构造函数在main之前调用,因为我们已在全局范围内声明了类A的对象:(我已经扩展了示例以演示如何在main执行之前创建线程)
#include <iostream>
#include <stdlib.h>
#include <pthread.h>
using namespace std;
void *fun(void *x)
{
while (true) {
cout << "Thread\n";
sleep(2);
}
}
pthread_t t_id;
class A
{
public:
A()
{
cout << "Hello before main \n " ;
pthread_create(&t_id, 0, fun, 0);
sleep(6);
}
};
A a;
int main()
{
cout << "I am main\n";
sleep(40);
return 0;
}