2008-12-31 13 views
5

quiero hacer este simple trabajo de código.Pasando punteros a la función en 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)); 
    } 

estoy en windows, usando vs. Cualquier ayuda será muy solicitada.

+1

¿Cuál es exactamente el problema? – Brian

Respuesta

6

En lo personal, yo no consideraría que pasa en un puntero de función que usted está tratando para hacer como muy C++ como. Eso es codificación C en C++

En cambio, envolvería esa cosa en una clase. La gran ventaja es que puedes anular la clase para tener tantos miembros como desees, en lugar de tener que realizar grandes trucos de lanzamiento para obtener tus parámetros todo el tiempo.

El código es un poco largo, así que lo empujé hasta el final. Pero lo que le permite hacer es algo como esto:

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

Aquí hay un código de ejemplo exerpted de una de nuestras clases que hace esto:

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

... y en el .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

Usted puede leer cómo se hace eso aquí: http://www.newty.de/fpt/fpt.html

2,6 Cómo pasar un puntero a función como un argumento?

Puede pasar un puntero a la función como un argumento de llamada de la función . Necesita esto, por ejemplo, si desea pasar un puntero a una función de devolución de llamada. El siguiente código muestra cómo pasar un puntero a una función que devuelve un int y toma un flotador y dos carac:

//------------------------------------------------------------------------------------ 
// 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

gracias que funciona bastante bien – SMeyers

11

CreateThread quiere 2 argumentos: puntero a la función de ejecutar como un hilo y un argumento DWORD que se le dará al hilo. su función spawnThread() solo tiene 1 argumento (threadName); piensa que tiene 2 argumentos debido a la "i", pero eso es realmente parte de la definición del tipo "nombre de secuencia". (. Usted podría así dejar de lado la "i", es decir, que no es necesario nombrar a los argumentos "threadName")

todos modos, teniendo en cuenta que se necesitan de 2 argumentos, redefinir spawnThread:

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

nótese que no nombre el argumento int para el threadEntryPoint; es suficiente decirle al compilador que la función debe tener un único argumento int.

y llamarlo:

spawnThread(printSome, 155); 

todos modos, rápido y sucio, esto va a hacer lo que quiere.

hth.

reilly.

5

No se puede pasar información de parámetro en un puntero de función; debe pasar por separado. Es exactamente por eso que la función CreateThread proporciona un parámetro void * que puede apuntar a lo que quieras.

Además, debe use _beginthread instead of CreateThread para aplicaciones C++.

Finalmente, es muy probable que su programa termine antes de que se ejecute el subproceso. Por lo tanto, debe ingresar un ciclo indefinido o usar una llamada API para esperar a que el hilo termine.

La siguiente es una versión funcional que usa WaitForSingleObject para bloquear hasta que se complete la secuencia.

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

Aquí es un C++/forma mucho más orientado a objetos de manejar esta misma situación:

#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

Gran respuesta, excepto que debe usar _beginthread() o _beginthreadex() en lugar de CreateThread(). Consulte http://stackoverflow.com/questions/331536/windows-threading-beginthread-vs-beginthreadex-vs-createthread-c para obtener más detalles. –

+0

Es cierto, actualicé la respuesta. ¡Había demasiadas cosas para arreglar! ;) –

4

Como mucha gente ya mencionó aquí, no se puede pasar un puntero de función y el argumento con el que se debe invocar en un parámetro.

Su línea

spawnThread(printSome(155)); 

"debería" (en el mundo DWIM) significa "Invocar printSome en un hilo separado con el argumento 155". Sin embargo, no es cómo C++ lo entiende. C++ ve "Pase el resultado de printSome invocado en 155 como un parámetro para spawnThread". En otras palabras, la secuencia de pasos es:

  • call prinotAlguno con 155 como argumento. Guárdelo en memoria temporal.
  • llamada spawn Enhebrar con los contenidos de la memoria temporal como argumento.

Para hacer lo que realmente quiere decir, tiene que humor C++ y separar el argumento de la función. Cómo hacerlo ya se explica en otras respuestas. El cortocircuito es:

callOnOtherThreadWithArgument (function, integer);

Cuestiones relacionadas