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

Posted

技术标签:

【中文标题】传递线程例程多个变量和堆栈大小【英文标题】:Passing thread routine multiple variables & stack size 【发布时间】:2011-06-03 22:04:50 【问题描述】:

在网络上的示例中,对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 本身线程启动例程: DWORD threadStartPointFuncStyleIWant(Data d);

所以我的问题真的是:

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

【问题讨论】:

【参考方案1】:

CreateThread 仅接受一种类型的函数,即采用单个 LPVOID 参数的函数。无法与 kernel32.dll 通信,这是调用线程函数的代码,它应该使用任何其他参数列表调用它。内核总是以同样的方式调用函数。

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

欢迎您在该结构中传递另一个函数指针,或传递一个带有自己方法的对象。然后你的线程过程就变成了解包LPVOID参数并分派到另一个函数指针或方法的东西,在那里你为线程做所有真正的工作。

【讨论】:

【参考方案2】:

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

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

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

Rgds, 马丁

【讨论】:

【参考方案3】:

除了 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;

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

【讨论】:

以上是关于传递线程例程多个变量和堆栈大小的主要内容,如果未能解决你的问题,请参考以下文章

huawei

Linux多线程

一个进程最多包含多少个线程

python多线程总结

实时监控 Java 中的总线程堆栈大小

最大线程堆栈大小.NET?