C++、线程和指针
C++, threads, and pointers
我正在使用std::thread来执行多个线程。 我将指向数组的指针作为参数传递,类似于:
my_type* rest[count];
//Fill rest array
std::thread(fnc, rest, count);
我似乎遇到的问题是,在此过程中的某个地方,"rest"中的指针值被损坏了。 我在调用 std::thread 之前打印出指针值,并在函数中打印出 std::thread 代表我调用的第一件事,并且值不匹配。 这似乎是相当随机的,有时它们会匹配,有时不会(当后者发生时,会产生段错误(。
我知道(从我能找到的关于这个主题的很少(std::thread 复制了参数,我认为我的问题源于此,并且有一个特殊的函数 std::ref(( 允许它传递引用,但没有一个特别提到指针。 我已经尝试了各种技术来尝试使用 std::ref(( 传递这个数组,但我还没有解决这个问题。
我是否正确认为这可能是我问题的原因,还是我吠错了树?
如果以某种方式(数组指针,而不是内容(进行转换,那么我会遇到问题。
是的,这正是发生的事情。
人们经常错误地说数组只是指针。事情的真相是,每当你声明一个接受数组的函数时:
void foo(int x[10]);
声明被"调整",以便参数是一个指针:
void foo(int *x); // C++ can't tell the difference between this and the first declaration
当你调用函数时:
int x[10];
foo(x);
有一个隐式转换等效于以下内容:
int x[10];
int *tmp = &x[0];
foo(tmp);
因此,发生的情况是,您有一个内存块,其中包含指向长寿命对象的指针:
my_type *rest[count] = {new my_type, new my_type, new my_type};
将指向该内存块的指针传递给线程:
thread(fnc, &rest[0], count);
然后,当函数返回时rest
超出范围,并且该内存块不再有效。
然后线程跟随指向内存块的指针并读取垃圾。如果碰巧它确实读取了正确的数组内容,那么它可以很好地访问长期存在的对象。问题是从损坏的内存块中获取指向长期存在的对象的指针,rest
曾经位于堆栈上。
有没有办法抑制这种行为?
在大多数情况下,唯一有意义的事情是不使用原始数组作为函数参数。您可以将原始数组包装在结构中并获得明智的行为:
struct int_array {
int x[10];
};
void foo(int_array x);
int main() {
int_array x = {1,2,3,4,5,6,7,8,9,0};
foo(x); // the array is copied rather than getting strangely converted
}
这几乎正是std::array
所做的,所以你最好使用它。
如果您不想要数组的副本,则可以引用该数组:
int foo(int (&x)[10]);
这为您提供了与背后用int foo(int x[10]); foo(x);
完成的奇怪"调整"和隐式转换基本相同的行为。这样做的好处是它是显式的,并且可以对数组的大小进行类型检查。也就是说,由于"调整",以下内容不会导致编译器错误:
int foo(int x[10]);
int x[3];
foo(x);
而这将:
int foo(int (&x)[10]);
int x[3];
foo(x); // the implicit conversion to &x[0] does not get happen when the function takes a reference to array
为了了解代码的风险,请尝试执行以下命令:
#include <thread>
#include <iostream>
void f() { std::cout << "hello" << std::endl; }
int main()
{
{
auto t = std::thread(f);
std::cout << "0" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::cout << "1" << std::endl;
}
std::cout << "2" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(400));
std::cout << "3" << std::endl;
}
您将看到2
,3
永远不会输出,因为应用程序已终止。
事实上,它更微妙,因为在我的样本中,我已经将线程移动到t
.类似于原始示例并且未将线程分配给任何变量,没有提前终止,但"hello"
永远不会输出。(可能有一个优化来消除临时的,因为它从未被使用过;它只是在可加入之前被摧毁了;或者谁知道呢......
- 如何检索指向在单独线程上运行的函数的移动指针?
- 如何将'this'指针传递给C++ WinAPI 线程?
- 从子线程访问指针
- 将字符串指针传递到C++和Xcode 11.1中不同线程上运行的函数
- 通过std::shared_ptr使用Rcpp和RcppParallel的线程安全函数指针
- 在多线程函数中返回共享的常量指针会导致计时问题吗?
- 线程中的成员函数指针
- 如何安全地终止线程?(使用指针)C++
- 指向成员对象的指针 - 中断线程
- 是否可以访问非线程安全容器内指针指向的值(线程安全映射中的条目)?
- 如何抓取指向Qt中弹出对话框的指针,该对话框阻止了QTest中的UI线程
- 将指针传递到另一个线程的正确方法
- CPP:如何使用需要指针的方法创建线程
- 启动线程会导致指针初始化时出现分段错误
- 是否访问指针元组和互斥锁线程安全
- 在容器中存储指向对象的指针时的线程安全
- 为什么当我在构造函数中创建线程时,实例化对象和对象的指针的行为不同
- 指针在不同的线程中获得错误的价值
- C++ 线程函数指针实现返回错误无效使用非静态成员函数
- 指向对象初始化的静态指针——线程安全