传递线程例程多个变量和堆栈大小

Passing thread routine multiple variables & stack size

本文关键字:堆栈 变量 线程 例程      更新时间:2023-10-16

在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;
}

要非常小心,不要将源自堆栈的指针传递给生成线程。