【问题标题】:Passing function Pointers in C++在 C++ 中传递函数指针
【发布时间】:2010-09-29 00:21:07
【问题描述】:

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

#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++ windows multithreading function pointers


【解决方案1】:

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

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

然后调用它:

   spawnThread(printSome, 155);

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

第一次。

赖利。

【讨论】:

    【解决方案2】:

    就个人而言,我不会考虑像您尝试做的那样传递函数指针,就像 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());
    
    }
    

    【讨论】:

      【解决方案3】:

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

      此外,对于 C++ 应用程序,您应该 use _beginthread instead of CreateThread

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

      以下是使用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;
      }
      

      这里有一个更 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;
      }
      

      【讨论】:

      • 很好的答案 - 除非您应该使用 _beginthread() 或 _beginthreadex() 而不是 CreateThread()。有关详细信息,请参阅stackoverflow.com/questions/331536/…
      • 没错,我更新了答案。有太多的事情要解决! ;)
      【解决方案4】:

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

      你的线路

          spawnThread(printSome(155));
      

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

      • 以 155 作为参数调用 prinotSome。将其存储在临时内存中。
      • 以临时内存的内容作为参数调用 spawnThread。

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

      callOnOtherThreadWithArgument(函数,整数);

      【讨论】:

        【解决方案5】:

        您可以在此处阅读您的操作方法: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);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-06-16
          • 2020-12-10
          • 1970-01-01
          • 2021-10-05
          • 1970-01-01
          相关资源
          最近更新 更多