2011-06-03 38 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; 
} 

要非常小心,不通過發起指針把堆放到產卵線上。