2014-11-19 82 views
1

我有一个C++ 11函数针对传统C函数进行调用。我认为创建工作线程(使用std::thread然后将变量传递给C函数)会很好,但是,如果线程等待执行时间太长,那么指针不再指向内存中的有效位置。为什么原始指针值被覆盖/超出范围

例(短路为了简洁/可读性,显然不是生产代码,但再现了问题)。

//The C function 
void c_func(const char* str1, const char* str2, const char* str3){ 

    printf("My strings str1: %s, str2: %s, str3: %s\n", str1, str2, str3); 
} 

... 

//C++ calling the function from numerous threads 
std::vector<std::thread> threads; 
std::vector<std::vector<std::string>> bar; 
... 
for (auto const& foo : bar) 
    { 
     threads.push_back(std::thread(c_func, foo[0].c_str(), foo[1].c_str(), (foo[0] + foo[1]).c_str())); 
    } 

打印输出结果将在不同的随机时间打印输出的垃圾一些试验后,我发现这确当我改变“C函数”来使用std::string而不是const char*时不会发生,但是这种改变意味着大量的重写代码...我宁愿不这样做...

有没有办法允许这种类型的多线程调用没有指针指向垃圾如果线程没有及时执行?或者我坚持重写遗留代码将其移至C++ ...

+4

你给出的指针只对'std :: string's的生命周期有效,然后欢快地继续做你在那个线程上做的任何事情,可能会抛弃一些'std: :一路上的字符串。这基本上是打破了,没有办法绕过它。这与在普通数据结构中存储'char *'没有任何区别,删除'string',然后从存储它们的地方获取'char *'。让你的生活在一起。 – delnan 2014-11-19 19:34:42

+0

@delnan Gotcha,感谢您的意见......这是我怀疑的,但不想相信的。 – 2014-11-19 19:37:03

+2

即使没有线程,'(foo [0] + foo [1])。c_str();'将返回垃圾,因为临时字符串将在完整的表达式求值后被销毁。 – 2014-11-20 02:36:02

回答

7

因为c_str()不会阻止清理字符串。在函数返回并清除bar之后,foo字符串也将被清理,这可能在线程启动之前。

你应该通过实际std::string(可能是一个包装,然后调用func之前提取char*)或以其他方式确保琴弦不会得到清理你join()编所有的线程之前。

+0

包装的想法也出现在我的脑海里。两者都是最好的,不必重写旧代码,但仍能保证线程持续时间的指针寿命。 – 2014-11-19 19:47:40

7

这里的线程的核心问题是父线程会在这些指针的另一端执行内存操作,使它们无效。

你需要做的是将std::string传递给每个线程。不是参考,不是指针,而是拷贝。现在每个线程都拥有自己的字符串副本,该副本将通过堆栈和析构函数的魔术自动清除。

现在您可以在每个字符串副本上调用c_str()以获取对该线程有效且不在其他范围内清理的指针。