我想使用5个线程打印内容为1,2,3,4,5的字符串,我的工作环境:
操作系统版本: CentOS Linux版本7.0.1406 (核心)
g++版本: g++ (GCC) 4.8.2 20140120 (红帽4.8.2-16)
编译cmd: g++ -o thread_sz -std=c++11 -pthread thread_sz.cpp
// file name: thread_sz.cpp
#include <iostream>
#include <string>
#include <thread>
#include <unistd.h>
using namespace std;
void myFunc1(char* sz)
{
printf("sz = %s\n", sz);
}
void myFunc2(const char* const sz)
{
printf("const char* const sz = %s\n", sz);
}
void myFunc3(string str)
{
printf("string str = %s\n", str.c_str());
}
int main(int argc, char* argv[])
{
for(int i = 1; i <= 5; i++) {
char sz[16];
sprintf(sz, "%2d", i);
const string str(sz);
std::thread t1(myFunc1, sz);
std::thread t2(myFunc2, (const char* const)str.c_str());
std::thread t3(myFunc3, str);
t1.detach();
t2.detach();
t3.detach();
}
usleep(1000000); // sleep 1 second
return 0;
}输出类似于:
const char* const sz = 1
sz = 3
const char* const sz = 2
string str = 3
sz = 4
sz = 4
string str = 2
sz = 5
const char* const sz = 4
sz = 5
string str = 1
const char* const sz = 5
string str = 4
string str = 5
const char* const sz = 5我运行了很多次这个程序,结果似乎:
string str output: 100% correct
sz output: ~10% correct
const char* const sz output: ~50% correct我的问题是:
1、为什么MyFunc1和MyFunc2不是100%正确的,两者有什么区别?如何修复它。
2、MyFunc3能否100%正确工作。
3 .如果我注释掉这一行,usleep(1000000); // sleep 1 second MyFunc1可能会输出空值,比如sz =,为什么?
非常感谢。
发布于 2015-02-04 12:02:54
在每一个循环周期中,您都会创建变量(字符数组和字符串对象),并将其传递给在新的独立线程中运行的myFuncX。主线程中的循环通常会进入下一个周期,但是其中一个线程在这个循环中启动并运行myFuncX没有完成它的运行。
函数行为之间的差异取决于参数的类型。myFunc1等待char*输入,因此指向字符(数组)的指针。主循环在每个循环中创建一个新的字符数组,并将其指针传递到myFunc1。但是这个数组是一个局部变量,所以它的内容只在这个循环中有效。如果主循环步骤到下一个周期,以前传递给myFunc1的参数的内容是不确定的,因为它指向一个内存位置,其中被破坏的局部变量是。这就是为什么有时或经常该方法写入错误值的原因。
在myFunc2的情况下也会发生同样的事情。不同的是,myFunc2等待一个指向字符串对象的字符数组的const *指针,但是这个字符串对象也是一个局部变量,因此它在每个循环结束时也会被销毁。
但是,在myFunc3的情况下,方法等待字符串对象而不是指针。当您将其传递给myFunc3时,将在方法中创建一个新对象,该方法的内容与主循环中创建的字符串相同。--但是这个对象是一个不同的对象,只有它的内容是相同的。因此,主循环中创建的字符串所发生的一切都是一样的,使用了它自己的本地string对象,因此打印将是完美的。
发布于 2015-02-04 12:09:10
我的答案是:
sprintf()将发生在for循环的下一次迭代中。
1.1。理论上,MyFunc2使用一个字符串,但是它使用的物理字符串变量与下一次重写的方式完全相同。在这种情况下,您拥有的运气比理性更多,因为字符串很可能在循环结束时被销毁,并且在下一次迭代中创建了一个新的字符串,这涉及重新分配内存并重新分配它,至少在理论上是这样--您只是幸运的是,这个新创建的字符串得到了与以前完全相同的指向新分配内存的指针。实际上,您正在传递一个悬空指针,幸运的是,该指针的值与新分配的数组相同(在使用str.c_str()并执行除立即复制或处理以外的任何操作以代替返回的字符数组时总是发生这种情况)。std::string类型变量中-因此,与1和2相比,从sz的读取发生在线程构造时,而不是在执行线程函数时。实际上,除了它自己的变量之外,您的函数不引用任何变量。但是,仍不能保证为上一次迭代排定的函数将在该函数为下一次迭代排定之前完成其工作。您可能不会在您的情况下观察到它,但理论上可能MyFunc3可以打印值而不是按迭代顺序打印(例如,前一个迭代中的线程被分配给另一个系统轻量级线程,而不是下一个迭代中的线程,而前一个迭代中的线程由于某种原因稍微延迟了--例如,您可能有一个情况,例如,4是打印在3之前的)。main()函数堆栈已经发布并可能被某种东西覆盖时,可能会触发您的函数。可能会发生,在你的情况下,这些是零。如果真是倒霉的话,你会有一长串随机二进制数据,直到程序到达没有分配给程序段的地址为止。
3.1。让程序进入睡眠状态只会延迟问题的时间,而不是解决问题。我建议您阅读thread::join(),甚至一般关于编写线程应用程序的文章。
https://stackoverflow.com/questions/28314970
复制相似问题