Pregunta

Quiero hacer este sencillo trabajo de código.

#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 apreciada.

¿Fue útil?

Solución

Personalmente, no consideraría pasar un puntero a una función como lo intentas hacer como a C ++. Eso es codificar C en C ++

En cambio, envolvería esa cosa en una clase. La gran ventaja es que puedes anular la clase para tener la cantidad de miembros que desees, en lugar de tener que realizar trucos de casting extravagantes para obtener tus parámetros en todo momento.

El código es un poco largo, así que lo empujé hasta el final. Pero lo que te 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 extraído 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());

}

Otros consejos

CreateThread quiere 2 argumentos: puntero a la función para ejecutarse 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 " i " ;, pero eso es realmente parte de la definición de " threadName " tipo. (también puede dejar de " i " ;; es decir, no es necesario que nombre los argumentos a " threadName ")

de todos modos, dado que NECESITA 2 argumentos, redefina spawnThread:

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

observe que no le puse nombre el argumento int al threadEntryPoint; es suficiente decirle al compilador que la función debe tener un solo argumento int.

y llámalo:

   spawnThread(printSome, 155);

De todos modos, rápido y sucio, esto hará lo que quieras.

hth.

Reilly.

No puede pasar información de parámetros en un puntero de función; Se debe pasar por separado. Esa es exactamente la razón por la que la función CreateThread proporciona un parámetro void * que puede apuntar a lo que quieras.

Además, debes usar _beginthread en lugar de CreateThread para aplicaciones C ++.

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

La siguiente es una versión de trabajo que utiliza WaitForSingleObject para bloquear hasta el hilo se completa.

#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í hay una forma mucho más orientada a C ++ / objeto 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;
}

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

Tu 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 así como C ++ lo entiende. C ++ ve " Pase el resultado de printSome invocado en 155 como un parámetro para engendrar Thread " ;. En otras palabras, la secuencia de pasos es:

  • llame a prinotSome con 155 como argumento. Guárdelo en la memoria temporal.
  • llame a spawnThread con el contenido de la memoria temporal como su argumento.

Para hacer lo que realmente quieres decir, debes interpretar C ++ y separar el argumento de la función. Cómo hacerlo ya está explicado en otras respuestas. El resumen es:

callOnOtherThreadWithArgument (función, entero);

Puede leer cómo lo hace 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 de función como   argumento llamante de la función. Necesitas   esto, por ejemplo, si desea pasar una   puntero a una función de devolución de llamada. los   siguiente código muestra cómo pasar una   puntero a una función que devuelve una   Int y toma un flotador y dos 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);
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top