2008-12-31 98 views
5

我想做這個簡單的代碼工作。傳遞函數C++中的指針

#include <iostream> 
#include <windows.h> 


    void printSome (int i) 
    { 
     std::cout << i << std::endl; 
    } 

    void spawnThread (void (*threadName)(int i)) 
    { 
     CreateThread 
      (
       0,  // default security attributes 
       0,   // use default stack size 
       (LPTHREAD_START_ROUTINE)threadName, // thread function name 
       (LPVOID)i,   // argument to thread function 
       0,   // use default creation flags 
       0  // returns the thread identifier 
      ); 
    } 

    int main() 
    { 
     spawnThread(printSome(155)); 
    } 

我在windows上,使用vs任何幫助將大大appriciated。

+1

那究竟是什麼問題呢? – Brian 2008-12-31 17:30:50

回答

6

就個人而言,我不會考慮傳遞一個函數指針像你正在嘗試做非常像C++一樣。這是C++中的C編碼

相反,我會把這個東西包裝在一個類中。最大的好處是你可以重寫這個類,讓它擁有你想要的許多成員,而不是每次都必須執行灰色鑄造技巧來獲取你的參數。

該代碼有點冗長,所以我把它推到最後。但是,你做什麼它可以是這樣的:

class print_some : public basic_thread { 
    private: 
     int i; 
    public:  
     print_some (int i) : i(i) {}; 
     action_callback() { 
      std::cout << i << std::endl; 
     } 
    } 
    int main() { 
     print_some printer (155); 
    } 

下面是做這個工作我們班的一個部分exerpted示例代碼:

class basic_thread : 
{ 
public: 
    basic_thread(); 
protected: 
    unsigned long m_ThreadId; 

    virtual void action_callback() {}; 

    // Internal routine used to bridge between OS callback format and 
    // action_callback. *Must* be static for the OS. 
    static unsigned long __stdcall self_calling_callback (void *parameter); 
} 

...在在.cpp:

unsigned long __stdcall basic_thread::self_calling_callback (void *parameter) { 
    if (parameter) { 
     basic_thread * thread = reinterpret_cast<basic_thread *>(parameter); 
     thread->action_callback(); 
    } 
    return 0; // The value returned only matters if someone starts calling GetExitCodeThread 
      // to retrieve it. 
} 

basic_thread::basic_thread() { 
    // Start thread. 
    m_Handle = CreateThread(NULL, 
          0, 
          self_calling_callback, 
          (PVOID)this, 
          0, 
          &m_ThreadId); 
    if(!IsHandleValid()) 
     throw StartException("CreateThread() failed", GetLastError()); 

} 
1

你可以閱讀你如何做到這一點的位置:http://www.newty.de/fpt/fpt.html

2.6如何傳遞一個函數指針作爲參數?

您可以將函數指針作爲 函數的調用參數傳遞。例如,如果您想將 指針傳遞給回調函數,則需要使用 。所述 下面的代碼說明如何將 指針傳遞給它返回一個 int和需要的浮子和兩個char的函數:

//------------------------------------------------------------------------------------ 
// 2.6 How to Pass a Function Pointer 

// <pt2Func> is a pointer to a function which returns an int and takes a float and two char 
void PassPtr(int (*pt2Func)(float, char, char)) 
{ 
    int result = (*pt2Func)(12, 'a', 'b');  // call using function pointer 
    cout << result << endl; 
} 

// execute example code - 'DoIt' is a suitable function like defined above in 2.1-4 
void Pass_A_Function_Pointer() 
{ 
    cout << endl << "Executing 'Pass_A_Function_Pointer'" << endl; 
    PassPtr(&DoIt); 
} 
+0

謝謝,效果很好 – SMeyers 2008-12-31 14:09:17

11

的CreateThread希望2個參數:指針函數來執行作爲線程,以及一個將被賦予該線程的DWORD參數。你的spawnThread()函數只有1個參數(threadName);你認爲它有2個參數,因爲「我」,但這實際上是「threadName」類型的定義的一部分。 (你也可以同樣離開了「我」;也就是說,你不需要命名參數「threadName」)

無論如何,因爲你需要2個參數,重新定義spawnThread:

void spawnThread(void (*threadEntryPoint)(int), int argument) 
    { 
     CreateThread(0,0, 
        (LPTHREAD_START_ROUTINE)threadEntryPoint, 
        (LPVOID)argument, 
        0,0); 
    } 

通知我沒有名稱 int參數給threadEntryPoint;告訴編譯器該函數必須有一個int參數就足夠了。

,並稱之爲:

spawnThread(printSome, 155); 

無論如何,快速和骯髒,這會做你想要什麼。

hth。

reilly。

5

您不能在函數指針中傳遞參數信息;它必須分開傳遞。這就是爲什麼CreateThread函數提供了一個void *參數,可以指向任何你想要的。

另外,您應該爲C++應用程序提供use _beginthread instead of CreateThread

最後,在線程運行之前,您的程序很可能會終止。因此,您必須輸入無限循環或使用API​​調用來等待線程完成。

以下是使用WaitForSingleObject阻止的工作版本,直到線程完成。

#include <iostream> 
#include <process.h> 
#include <windows.h> 

void 
printSome(int i) 
{ 
    std::cout << i << std::endl; 
} 

HANDLE 
spawnThread(void (*threadName)(int), int i) 
{ 
    return (HANDLE) _beginthread((void (*)(void*)) threadName, 0, (LPVOID) i);  
} 

int 
main(int argc, char *argv[]) 
{ 
    HANDLE threadHandle; 

    threadHandle = spawnThread(printSome, 155); 
    WaitForSingleObject(threadHandle, INFINITE); 

    return 0; 
} 

這裏是一個更加C++ /面向對象的處理這種情況相同的方式:

#include <iostream> 
#include <process.h> 
#include <windows.h> 

class Thread { 
    static void proxy(void *arg) { (*(reinterpret_cast<Thread *> (arg)))(); } 
    HANDLE thread_; 

public: 
    virtual ~Thread() {} 
    virtual void operator()() = 0; 
    void start() { thread_ = (HANDLE) _beginthread(Thread::proxy, 0, this);}  
    void waitForExit() { WaitForSingleObject(thread_, INFINITE); } 
}; 

class Printer : public Thread { 
    int i_; 

public: 
    Printer(int i) : i_(i) {} 
    void operator()() { std::cout << i_ << std::endl; } 
}; 

int 
main(int argc, char *argv[]) 
{ 
    Printer p(155); 

    p.start(); 
    p.waitForExit(); 

    return 0; 
} 
+0

偉大的答案 - 除了你應該使用_beginthread()或_beginthreadex(),而不是CreateThread()。有關更多詳細信息,請參閱http://stackoverflow.com/questions/331536/windows-threading-beginthread-vs-beginthreadex-vs-createthread-c。 – 2008-12-31 15:19:39

4

正如很多人已經在這裏提到的那樣,您不能在一個參數中傳遞函數指針和應該調用的參數。

你行

spawnThread(printSome(155)); 

「應該」(在世界DWIM)的意思是 「調用printSome與參數155一個單獨的線程」。但是,C++並不是如此理解它。 C++看到「將printSome的結果作爲spawnThread的參數傳遞給155」。換句話說,步驟的順序是:

  • 調用prinotSome用155作爲參數。將其存儲在臨時內存中。
  • 以臨時內存的內容爲參數調用spawnThread。

爲了做到你真正的意思,你必須幽默C++和從函數分離參數。如何做到這一點已在其他答案中解釋。它的缺點是:

callOnOtherThreadWithArgument(function,integer);