Вопрос

Я хочу выполнить этот простой фрагмент кода.

#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.Любая помощь будет очень оценена.

Это было полезно?

Решение

Лично я бы не рассматривал возможность передачи указателя на функцию, как вы пытаетесь сделать, как в 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);
    }

Вот пример кода одного из наших классов, который делает это:

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

}

Другие советы

CreateThread требует 2 аргумента:указатель на функцию, которая будет выполняться как поток, и аргумент DWORD, который будет передан потоку.ваша функция spawnThread() имеет только 1 аргумент (threadName);ты думать у него есть 2 аргумента из-за «i», но на самом деле это часть определения типа «threadName».(с таким же успехом вы могли бы опустить «i»;то есть вам не нужно называть аргументы «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);

в любом случае, быстро и грязно, это сделает то, что вы хотите.

хт.

Рейли.

Вы не можете передать информацию о параметрах в указателе функции;его необходимо передать отдельно.Именно поэтому функция CreateThread предоставляет параметр void*, который может указывать на все, что вы хотите.

Кроме того, вам следует используйте _beginthread вместо CreateThread для приложений C++.

Наконец, ваша программа, скорее всего, завершится до того, как поток запустится.Поэтому вам придется либо ввести неопределенный цикл, либо использовать вызов API, чтобы дождаться завершения потока.

Ниже приведена рабочая версия с использованием Ждатьфорсинглеобъект для блокировки до завершения потока.

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

Как многие люди уже упоминали здесь, вы не можете передать указатель на функцию и аргумент, с которым она должна быть вызвана, в одном параметре.

Ваша линия

    spawnThread(printSome(155));

«должен» (в мире DWIM) означает «вызвать printSome в отдельном потоке с аргументом 155».Однако C++ понимает это не так.С++ видит «Передать результат printSome, вызванного в 155, в качестве параметра для spawnThread».Другими словами, последовательность шагов такова:

  • вызовите prinotSome с аргументом 155.Сохраните его во временной памяти.
  • вызовите spawnThread с содержимым временной памяти в качестве аргумента.

Чтобы сделать то, что вы действительно имеете в виду, вам нужно позаботиться о C++ и отделить аргумент от функции.Как это сделать, уже описано в других ответах.Вкратце это:

callOnOtherThreadWithArgument (функция, целое число);

Вы можете прочитать, как это сделать, здесь: http://www.newty.de/fpt/fpt.html

2.6 Как передать указатель на функцию в качестве аргумента?

Вы можете передать указатель функции в качестве аргумента вызова функции.Вам нужно это, например, если вы хотите передать указатель на функцию обратного вызова.Следующий код показывает, как передать указатель на функцию, которая возвращает Int и берет поплавок и два чара:

//------------------------------------------------------------------------------------
// 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);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top