2011-06-03 100 views
1

在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本身线程启动例程:

 
DWORD threadStartPointFuncStyleIWant(Data d) ; 

所以我的问题是真的:

  • 对于螺纹起点(CreateThread的),是我们限制到功能与以下形式的原型:
 
DWORD validThreadFunc(LPVOID pParamStruct) ; 
  • 或者我们可以开始功能的线程像
 
DWORD threadFunc1(int p1, int p2) ; 
DWORD threadFunc2(Data d) ; 

回答

7

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

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

欢迎您在该结构中传递另一个函数指针,或者使用它自己的方法传递一个对象。然后,你的线程程序就成为了解开LPVOID参数并分派给其他函数指针或方法的地方,在那里你为线程做了所有真正的工作。

2

做你想做的事情,虽然不是不可能,但是编译器和操作系统之间需要这么多的合作,以至于操作系统的设计目标会受到影响。

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

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

RGDS, 马丁

0

您可以使用Boost线程库除的boost :: bind调用得到的东西像你想:

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

要非常小心,不通过发起指针把堆放到产卵线上。