传递线程例程多个变量和堆栈大小
Passing thread routine multiple variables & stack size
在web上的示例中,对CreateThread的调用通常会为LPVOID lpParameter
传递一个指向结构的指针,然后使用该指针来访问结构本身。
#include <Windows.h>
#include <stdio.h>
struct Point
{
float x,y,z ;
} ;
DWORD WINAPI threadStartPoint( LPVOID data )
{
Sleep( 1000 ) ;
Point *p = (Point*)data ;
printf( "%f %f %fn", p->x, p->y, p->z ) ;
puts( "Thread job done" ) ;
return 0 ;
}
// From main
int main()
{
DWORD threadId ;
Point p ;
p.x=2, p.y=3, p.z=4 ;
HANDLE handle = CreateThread( 0, 0,
threadStartPoint,
(LPVOID)&p,
0, // ?? I think I should be using this parameter</b>
&threadId
) ;
if( !handle )
{
// Thread creation failed
puts( "start failn" );
}
else
{
printf( "started on threadid=%dn", threadId ) ;
}
WaitForSingleObject( handle, 2000 ) ; // wait up to 2000 ms for the other thread to complete before moving on
puts( "main thread Exiting.." ) ;
//system( "pause" ) ;
}
我发现这有点不方便,因为您必须确保结构存在,并确保在线程完成执行时正确地销毁它。
我想启动我的线程,但将正常堆栈参数即自动变量,或者struct
本身传递给线程启动例程:
DWORD线程起始点FuncStyleIWant(数据d);
所以我的问题是:
- 对于线程起点(CreateThread),我们是否仅限于具有以下形式原型的函数:
DWORD有效线程函数(LPVOID pParamStruct);
- 或者我们可以在函数上启动一个线程,比如
DWORD线程Func1(int p1,int p2);DWORD线程Func2(数据d);
CreateThread
只接受一种类型的函数,即接受单个LPVOID
参数的函数。没有办法与kernel32.dll(调用线程函数的代码)通信,它应该使用任何其他参数列表来调用它。内核总是以相同的方式调用函数。
你只需要像其他人一样继续做下去。在堆上分配结构,将指针传递给线程例程,然后在从线程例程返回之前释放它。也就是说,所有权从始发线程转移到新线程。一旦新线程获得所有权,您就可以使用像shared_ptr
这样的智能指针来确保无论您离开线程,它都会被释放。
欢迎您在该结构中传递另一个函数指针,或者传递具有自己方法的对象。然后,您的线程过程只不过是对LPVOID
参数进行解包并将其分派到另一个函数指针或方法,在那里您为线程执行所有实际工作。
做你想做的事情虽然不是不可能,但需要编译器和操作系统之间的大量合作,以至于操作系统的设计目标会受到影响。
要创建一个线程,操作系统必须分配一个堆栈并对其进行初始化,这样堆栈框架的顶部看起来就像线程之前一直在运行并被中断一样。为了启动第一次执行的线程,操作系统会执行中断返回,即操作系统从不调用线程,它们总是返回到。为了提供可变的参数格式,操作系统需要知道参数块的长度,这样它就可以在中断帧被推送之前将参数从调用线程堆栈复制到新线程的堆栈。你看到这变得有多混乱了吗?如果ctor线程和新线程有不同的调用约定,会发生什么?
只传递一个可以在寄存器中"传递"的指针参数更容易/更安全。在像C++这样的OO语言的情况下,这将是"this",这样新线程就可以访问自己的数据成员和vtable指针。
Rgds,Martin
除了Boost::bind调用之外,您还可以使用Boost线程库来获得您想要的东西:
#include <boostthread.hpp>
struct Point
{
float x,y,z;
};
void threadStartPoint( Point p )
{
Sleep( 1000 ) ;
printf( "%f %f %fn", p.x, p.y, p.z ) ;
}
int main(int argc, char** argv)
{
Point p;
p.x = 1;
p.y = 2;
p.z = 3;
// start the thread.
// first argument to "bind" is the worker thread function.
boost::thread t(boost::bind(threadStartPoint, p));
// wait for thread to exit
t.join();
return 0;
}
要非常小心,不要将源自堆栈的指针传递给生成线程。
- 堆栈变量超出范围时是否解除分配?
- 堆栈变量和函数C++奇怪的行为
- 野牛堆栈变量中的值分配
- 局部堆栈变量成员的返回值优化
- 访问其他线程堆栈变量如何在C++中工作?
- 指向堆栈变量的指针是否易失
- 是否可以 std::move 局部堆栈变量?
- 返回堆栈变量时停止调用析构函数
- 优化易失性堆栈变量的存储/构造是否合法
- SEGFAULT正在写入堆栈变量
- 汇编:C++堆栈变量地址不同/错误?
- C++11 Lambda闭包通过引用涉及一个堆栈变量,该变量离开作用域是允许的,但得到了未定义的行为
- 返回堆栈变量
- Visual Studio 在引用堆栈变量时不使用 EBP
- 堆栈变量或函数声明
- 访问堆栈变量的速度比取消引用指针慢
- 静态变量与堆栈变量:线程安全与堆栈大小
- 堆栈变量生存期好奇的例子
- 如何查找未初始化的堆栈变量
- 如何为堆栈变量分配内存