windows 在 C++ 中传递函数指针

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/402992/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 11:46:45  来源:igfitidea点击:

Passing function Pointers in C++

c++windowsmultithreadingfunctionpointers

提问by SMeyers

i want to do this simple piece of code work.

我想做这个简单的代码工作。

#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 on windows, using vs. Any help will be greatly appriciated.

我在 Windows 上,使用 vs. 任何帮助都会非常有用。

回答by reilly

CreateThread wants 2 arguments: pointer to the function to execute as a thread, and a DWORD argument that will be given to the thread. your spawnThread() function only has 1 argument (threadName); you thinkit has 2 args because of the "i", but that is really part of the definition of the "threadName" type. (you could just as well leave out the "i"; that is, you don't need to name the arguments to "threadName".)

CreateThread 需要 2 个参数:指向作为线程执行的函数的指针,以及将提供给线程的 DWORD 参数。您的 spawnThread() 函数只有 1 个参数 (threadName);由于“i”,您认为它有 2 个参数,但这实际上是“threadName”类型定义的一部分。(您也可以省略“i”;也就是说,您不需要将参数命名为“threadName”。)

anyway, given that you NEED 2 arguments, redefine spawnThread:

无论如何,鉴于您需要 2 个参数,请重新定义 spawnThread:

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

notice that i did not namethe int argument to the threadEntryPoint; it is sufficient to tell the compiler that the function must have a single int argument.

请注意,我没有将 int 参数命名为 threadEntryPoint;告诉编译器该函数必须有一个 int 参数就足够了。

and call it:

并称之为:

   spawnThread(printSome, 155);

anyway, quick and dirty, this will do what you want.

无论如何,又快又脏,这会做你想做的。

hth.

嗯。

reilly.

赖利。

回答by T.E.D.

Personally, I wouldn't consider passing in a function pointer like you are trying to do as very C++ like. That's coding C in C++

就个人而言,我不会考虑像您尝试像 C++ 那样传递函数指针。那就是用 C++ 编码 C

Instead, I'd wrap that thing in a class. The big advantage there is you can just override the class to have however many members you want, rather than having to perform greazy casting tricks to get at your parameters every time.

相反,我会将那个东西包装在一个类中。最大的优势是您可以覆盖该类以拥有您想要的任意数量的成员,而不必每次都执行繁琐的转换技巧来获取您的参数。

The code's a little long-winded, so I pushed it to the end. But what it lets you do is something like this:

代码有点啰嗦,所以我把它推到了最后。但它让你做的是这样的:

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

Here's some exerpted example code from one of our classes that does this:

下面是从我们的一个类中摘录的一些示例代码,用于执行此操作:

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

...and in the .cpp:

...并在 .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());

}

回答by Judge Maygarden

You cannot pass parameter information in a function pointer; it must be passed separately. That is exactly why the CreateThread function provides a void* parameter that can point to whatever you want.

不能在函数指针中传递参数信息;它必须单独通过。这正是 CreateThread 函数提供可以指向任何您想要的任何内容的 void* 参数的原因。

Additionally, you should use _beginthread instead of CreateThreadfor C++ applications.

此外,对于 C++ 应用程序,您应该使用 _beginthread 而不是 CreateThread

Finally, your program is more than likely to terminate before the thread ever runs. Therefore, you must either enter an indefinite loop or use an API call to wait for the thread to finish.

最后,您的程序很可能在线程运行之前终止。因此,您必须进入无限循环或使用 API 调用来等待线程完成。

The following is a working version using WaitForSingleObjectto block until the thread completes.

以下是使用WaitForSingleObject阻塞直到线程完成的工作版本。

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


Here is a much more C++/object-oriented way of handling this same situation:

这是处理相同情况的更多 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;
}

回答by SMeyers

As many people already mentioned here, you can't pass a function pointer and the argument it should be called with in one parameter.

正如许多人在这里已经提到的那样,您不能传递函数指针和应该在一个参数中调用它的参数。

Your line

你的线路

    spawnThread(printSome(155));

"should" (in DWIM world) mean "Invoke printSome on a separate thread with argument 155". However, it's not how C++ understands it. C++ sees "Pass the result of printSome invoked on 155 as a parameter to spawnThread". In other words, the sequence of steps is:

“应该”(在 DWIM 世界中)的意思是“使用参数 155 在单独的线程上调用 printSome”。但是,这不是 C++ 的理解方式。C++ 看到“将在 155 上调用的 printSome 的结果作为参数传递给 spawnThread”。换句话说,步骤的顺序是:

  • call prinotSome with 155 as argument. Store it in temporary memory.
  • call spawnThread with the contents of temporary memory as its argument.
  • 以 155 作为参数调用 prinotSome。将其存储在临时内存中。
  • 以临时内存的内容作为参数调用 spawnThread。

In order to do what you really mean, you have to humor C++ and separate argument from function. How to do it is already explained in other answers. The short of it is:

为了做你真正的意思,你必须幽默 C++ 并将参数与函数分开。其他答案中已经解释了如何做到这一点。它的短处是:

callOnOtherThreadWithArgument(function, integer);

callOnOtherThreadWithArgument(function, integer);

回答by Filip Ekberg

You can read how you do that here: http://www.newty.de/fpt/fpt.html

你可以在这里阅读你是如何做到的:http: //www.newty.de/fpt/fpt.html

2.6 How to Pass a Function Pointer as an Argument ?

You can pass a function pointer as a function's calling argument. You need this for example if you want to pass a pointer to a callback function. The following code shows how to pass a pointer to a function which returns an int and takes a float and two char:

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