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

时间:2011-06-03 22:04:50

标签: c++ windows multithreading

在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 %f\n", 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 fail\n" );
  }
  else
  {
    printf( "started on threadid=%d\n", 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存在,并确保在线程执行完毕后它被正确销毁。

我想开始我的线程,但是传递普通堆栈参数即自动变量,或者可能将struct本身传递给线程启动例程:

DWORD threadStartPointFuncStyleIWant( Data d ) ;

所以我的问题确实是:

  • 对于线程起始点(CreateThread),我们是否限制为具有以下形式原型的函数:
DWORD validThreadFunc( LPVOID pParamStruct ) ;
  • 或者我们可以在
  • 这样的函数上启动一个线程
DWORD threadFunc1( int p1, int p2 ) ;
DWORD threadFunc2( Data d ) ;

3 个答案:

答案 0 :(得分:7)

CreateThread只接受一种类型的函数,即接受单个LPVOID参数的函数。没有办法与kernel32.dll通信,它是调用你的线程函数的代码,它应该用任何其他参数列表调用它。内核总是以相同的方式调用函数。

你必须像其他人一样继续这样做。在堆上分配结构,将指针传递给线程例程,然后在从线程例程返回之前释放它。也就是说,所有权从原始线程传递到新线程。一旦新线程获得所有权,您就可以使用像shared_ptr这样的智能指针来确保它在您离开线程时被释放。

欢迎您在该结构中传递另一个函数指针,或者使用自己的方法传递一个对象。然后你的线程程序只不过是解压缩LPVOID参数并调度到另一个函数指针或方法的东西,你可以在那里完成线程的所有实际工作。

答案 1 :(得分:2)

做你想要的,虽然并非不可能,但需要在编译器和操作系统之间进行如此多的合作,以免影响操作系统的设计目标。

要创建一个线程,操作系统必须分配一个堆栈并对其进行初始化,以便堆栈帧的顶部看起来像线程之前一直在运行并被中断。为了首次启动线程执行,OS然后执行中断返回,即。操作系统从不调用线程,它们总是返回。为了提供可变的参数格式,OS需要知道参数块长度,以便在推入中断帧之前将参数从调用线程堆栈复制到新线程的堆栈。你看到这变得多么混乱?如果ctor线程和新线程有不同的调用约定会发生什么?

更容易/更安全地传递一个可以在寄存器中“传递”的指针参数。对于像C ++这样的OO语言,这将是'this',以便新线程可以访问自己的数据成员和vtable指针。

RGDS, 马丁

答案 2 :(得分:0)

除了boost :: bind调用之外,你还可以使用Boost线程库来获得你想要的东西:

#include <boost\thread.hpp>

struct Point
{
    float x,y,z;
};

void threadStartPoint( Point p )
{
  Sleep( 1000 ) ;
  printf( "%f %f %f\n", 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;
}

小心不要将源自堆栈的指针传递给产生线程。

相关问题