2008-12-31 49 views
5

tôi muốn thực hiện công việc mã đơn giản này.Chức năng truyền con trỏ trong 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)); 
    } 

i am trên windows, using vs. Bất kỳ trợ giúp nào sẽ được đánh giá cao.

+1

Vậy vấn đề chính xác là gì? – Brian

Trả lời

6

Cá nhân, tôi sẽ không xem xét thông qua trong một con trỏ hàm như bạn đang cố gắng để làm như rất C + + như thế nào. Đó là mã C trong C++

Thay vào đó, tôi muốn bọc thứ đó vào một lớp. Ưu điểm lớn đó là bạn chỉ có thể ghi đè lên lớp để có tuy nhiên nhiều thành viên mà bạn muốn, thay vì phải thực hiện thủ thuật đúc greazy để có được các thông số của bạn mỗi lần.

Mã này hơi dài, vì vậy tôi đã đẩy nó đến cuối. Nhưng những gì nó cho phép bạn làm là một cái gì đó như thế này:

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

Dưới đây là một số ví dụ mã exerpted từ một trong các lớp học của chúng tôi thực hiện điều này:

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

... và trong 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

Bạn có thể đọc như thế nào bạn làm điều đó ở đây: http://www.newty.de/fpt/fpt.html

2,6 Làm thế nào để Pass một Pointer Chức năng như một Đối số?

Bạn có thể truyền con trỏ hàm làm đối số gọi hàm của . Bạn cần ví dụ này nếu bạn muốn chuyển một con trỏ đến hàm gọi lại. Các mã sau đây cho thấy làm thế nào để vượt qua một con trỏ đến một chức năng mà trả về một int và mất một phao và hai 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

cảm ơn hoạt động khá tốt – SMeyers

11

CreateThread muốn 2 đối số: con trỏ đến các chức năng để thực hiện như một sợi và một đối số DWORD sẽ được đưa ra cho chuỗi. Hàm spawnThread() của bạn chỉ có 1 đối số (threadName); bạn nghĩ rằng nó có 2 arg vì "i", nhưng đó thực sự là một phần của định nghĩa kiểu "threadName". (. Bạn có thể chỉ cần cũng bỏ qua "i", đó là, bạn không cần phải đặt tên cho các đối số "threadName")

dù sao, cho rằng bạn CẦN 2 đối số, xác định lại spawnThread:

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

thông báo rằng tôi không tên đối số int cho threadEntryPoint; nó là đủ để nói với trình biên dịch rằng hàm phải có một đối số int duy nhất.

và gọi nó là:

spawnThread(printSome, 155); 

dù sao, nhanh chóng và dơ bẩn, điều này sẽ làm những gì bạn muốn.

hth.

reilly.

5

Bạn không thể chuyển thông tin tham số vào con trỏ hàm; nó phải được thông qua một cách riêng biệt. Đó chính là lý do tại sao hàm CreateThread cung cấp một tham số void * có thể trỏ tới bất cứ thứ gì bạn muốn.

Ngoài ra, bạn nên use _beginthread instead of CreateThread cho các ứng dụng C++.

Cuối cùng, chương trình của bạn có nhiều khả năng chấm dứt trước khi chuỗi chạy. Do đó, bạn phải nhập một vòng lặp không xác định hoặc sử dụng một cuộc gọi API để đợi cho đến khi chuỗi kết thúc.

Sau đây là phiên bản đang hoạt động sử dụng WaitForSingleObject để chặn cho đến khi chuỗi hoàn tất.

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

Đây là một C nhiều hơn nữa ++/hướng đối tượng cách xử lý tình huống tương tự này:

#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

Câu trả lời hay - ngoại trừ bạn nên sử dụng _beginthread() hoặc _beginthreadex() thay vì CreateThread(). Xem http://stackoverflow.com/questions/331536/windows-threading-beginthread-vs-beginthreadex-vs-createthread-c để biết thêm chi tiết. –

+0

Đúng, tôi đã cập nhật câu trả lời. Có quá nhiều thứ cần sửa! ;) –

4

Như nhiều người đã đề cập ở đây, bạn không thể chuyển một con trỏ hàm và đối số nó sẽ được gọi với trong một tham số.

dòng của bạn

spawnThread(printSome(155)); 

"nên" (trong thế giới DWIM) có nghĩa là "Gọi printSome trên một sợi riêng biệt với lập luận 155". Tuy nhiên, nó không phải là cách C++ hiểu nó. C++ thấy "Vượt qua kết quả của printSome được gọi trên 155 như một tham số để spawnThread". Nói cách khác, chuỗi các bước là:

  • gọi prinotMột số với 155 là đối số. Lưu trữ nó trong bộ nhớ tạm thời.
  • gọi spawnThread với nội dung của bộ nhớ tạm thời làm đối số của nó.

Để làm những gì bạn thực sự muốn nói, bạn phải hài hước C++ và đối số riêng biệt từ hàm. Làm thế nào để làm điều đó đã được giải thích trong câu trả lời khác. Phần ngắn của nó là:

callOnOtherThreadWithArgument (hàm, số nguyên);

Các vấn đề liên quan