Domanda

Voglio fare questo semplice lavoro di codice.

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

Sono su Windows, usando vs. Qualsiasi aiuto sarà molto apprezzato.

È stato utile?

Soluzione

Personalmente, non prenderei in considerazione l'idea di passare un puntatore a funzione come se stessi provando a fare un C ++. Questa è la codifica C in C ++

Invece, avvolgo quella cosa in una classe. Il grande vantaggio è che puoi semplicemente ignorare la classe per avere tutti i membri che desideri, piuttosto che dover eseguire trucchi di casting greazy per ottenere i tuoi parametri ogni volta.

Il codice è un po 'prolisso, quindi l'ho spinto fino alla fine. Ma ciò che ti consente di fare è qualcosa del genere:

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

Ecco un esempio di codice estratto da una delle nostre classi che esegue ciò:

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

... e nel .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());

}

Altri suggerimenti

CreateThread vuole 2 argomenti: puntatore alla funzione da eseguire come thread e un argomento DWORD che verrà dato al thread. la tua funzione spawnThread () ha solo 1 argomento (threadName); tu pensi ha 2 argomenti a causa di " i " ;, ma questo fa davvero parte della definizione di " threadName " genere. (potresti anche tralasciare "i", ovvero non è necessario nominare gli argomenti su "threadName").

comunque, dato che hai BISOGNO di 2 argomenti, ridefinisci spawnThread:

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

nota che non ho nominato l'argomento int sul threadEntryPoint; è sufficiente dire al compilatore che la funzione deve avere un singolo argomento int.

e chiamalo:

   spawnThread(printSome, 155);

comunque, veloce e sporco, questo farà quello che vuoi.

hth.

Reilly.

Non è possibile passare informazioni sui parametri in un puntatore a funzione; deve essere passato separatamente. Questo è esattamente il motivo per cui la funzione CreateThread fornisce un parametro void * che può puntare a quello che vuoi.

Inoltre, dovresti utilizzare _beginthread invece di CreateThread per applicazioni C ++.

Infine, è molto probabile che il tuo programma venga chiuso prima che il thread venga mai eseguito. Pertanto, è necessario immettere un ciclo indefinito o utilizzare una chiamata API per attendere il completamento del thread.

La seguente è una versione funzionante che utilizza WaitForSingleObject per bloccare fino al la discussione è completata.

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

Ecco un modo molto più C ++ / orientato agli oggetti di gestire questa stessa situazione:

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

Come molte persone già menzionate qui, non è possibile passare un puntatore a funzione e l'argomento con cui dovrebbe essere chiamato in un parametro.

La tua linea

    spawnThread(printSome(155));

" " opportuno; (nel mondo DWIM) significa "Richiama printSome su un thread separato con argomento 155". Tuttavia, non è il modo in cui C ++ lo capisce. C ++ vede " Passa il risultato di printSome invocato su 155 come parametro per spawnThread " ;. In altre parole, la sequenza dei passaggi è:

  • chiama prinotSome con 155 come argomento. Conservalo nella memoria temporanea.
  • chiama spawnThread con il contenuto della memoria temporanea come argomento.

Per fare ciò che realmente intendi, devi umorizzare il C ++ e separare l'argomento dalla funzione. Come farlo è già spiegato in altre risposte. Il corto è:

callOnOtherThreadWithArgument (function, integer);

Puoi leggere come farlo qui: http://www.newty.de/ FPT / fpt.html

  

2.6 Come passare un puntatore a funzione come argomento?

     

È possibile passare un puntatore a funzione come a   argomento di chiamata della funzione. Hai bisogno   questo ad esempio se si desidera passare a   puntatore a una funzione di richiamata. Il   il codice seguente mostra come passare a   puntatore a una funzione che restituisce un   int e accetta un float e due caratteri:

//------------------------------------------------------------------------------------
// 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);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top