【问题标题】:How to pass parameters to a Thread object?如何将参数传递给 Thread 对象?
【发布时间】:2010-10-16 20:14:57
【问题描述】:

我正在使用一个 C++ 类库,它提供了一个线程基类,用户必须在其中 实现一个run() 方法。

关于如何将参数传递给run() 方法,是否有推荐的方法?现在 我更喜欢通过构造函数(作为指针)传递它们。

【问题讨论】:

    标签: c++ multithreading concurrency


    【解决方案1】:

    我不确定 C++,但这就是你在 Java 中的做法。您将拥有一个扩展 Thread(或实现 Runnable)的类和一个带有您想要传递的参数的构造函数。然后,当您创建新线程时,您必须传入参数,然后启动线程,如下所示:

    Thread t = new MyThread(args...);
    t.start();
    

    在您的情况下必须相同。

    【讨论】:

    • 哈,Java 答案已被标记为 C++ 的问题接受:)
    • 这肯定不是这个问题的答案
    【解决方案2】:

    另一种方法是扩展此 Thread 类以接受函子作为唯一的构造函数参数,以便您可以在其中绑定任何调用。

    那么使用线程的类就不需要从 Thread 继承,而只有一个(或多个)Thread 成员。仿函数调用你想要的任何起点(带有任何参数的类的某些方法)

    【讨论】:

      【解决方案3】:

      这是一个典型的模式:

      1) 定义一个封装你线程需要的所有数据的数据结构 2) 在主线程中,使用 operator new 在堆上实例化数据结构的副本。 3) 填写数据结构,将指针转换为 void*,通过线程库提供的任何方式将 void* 传递给线程过程。 4)当工作线程得到void*时,它会将它重新解释为数据结构,然后取得对象的所有权。这意味着当线程处理完数据后,线程会释放它,而不是主线程释放它。

      这是您可以在 Windows 中编译和测试的示例代码。

          #include "stdafx.h"
          #include <windows.h>
          #include <process.h>
      
          struct ThreadData
          {
              HANDLE isRunning_;
          };
      
          DWORD WINAPI threadProc(void* v)
          {
      
          ThreadData* data = reinterpret_cast<ThreadData*>(v);
          if( !data )
              return 0;
      
          // tell the main thread that we are up & running
          SetEvent(data->isRunning_);
      
          // do your work here...
      
          return 1;
      }
      
      int main()
      {
          // must use heap-based allocation here so that we can transfer ownership
          // of this ThreadData object to the worker thread.  In other words, 
          // the threadProc() function will own & deallocate this resource when it's
          // done with it.
          ThreadData * data = new ThreadData;
          data->isRunning_ = CreateEvent(0, 1, 0, 0);
      
          // kick off the new thread, passing the thread data
          DWORD id = 0;
          HANDLE thread = CreateThread(0, 0, threadProc, reinterpret_cast<void*>(data), 0, &id);
      
          // wait for the worker thread to get up & running
          //
          // in real code, you need to check the return value from WFSO and handle it acordingly.  
          // Here I assume the retval is WAIT_OBJECT_0, indicating that the data->isRunning_ event 
          // has become signaled
          WaitForSingleObject(data->isRunning_,INFINITE); 
      
          // we're done, wait for the thread to die
          WaitForSingleObject(thread, INFINITE);
          CloseHandle(thread);
      
          return 0;
      
      }
      

      【讨论】:

        【解决方案4】:

        线程启动的一个常见问题是传递的参数只存在于调用函数的堆栈上。线程启动通常会被延迟,这样调用函数就会返回,并且仅在一段时间后线程才会真正启动 - 到那时参数不再存在。

        对此的一种解决方案是创建一个事件,然后启动线程,将该事件作为参数之一传递。启动函数然后等待事件,该事件由线程在完成启动时发出信号。

        【讨论】:

        • 我从未尝试过。令我印象深刻的是,您必须更改池中的线程数,因为工作负载会发生变化,这似乎是一个尴尬的复杂情况。
        【解决方案5】:

        您可以将参数作为线程类的成员传递。创建线程的线程大概可以在线程启动之前调用其他方法和/或调用成员函数。因此,它可以填充它工作所需的任何成员。然后当 run 方法被调用时,它就会有启动所需的信息。

        我假设您将为每个线程使用一个单独的对象。

        您通常会将您创建的所有线程放入数组、向量等中。

        【讨论】:

        • 使用 getter 方法的方法很好,但我认为我更喜欢通过 Thread 构造函数传递参数。我喜欢在调用构造函数后有一个可用的对象。
        【解决方案6】:

        可以通过构造函数传递它们。只要确保指针的寿命比线程长。

        【讨论】:

          【解决方案7】:

          好吧,我宁愿把参数放在 Start() 方法中,这样你就可以有一个受保护的构造函数,而不必通过派生类构造函数级联参数。

          我会让我的声明看起来像这样:

          class Thread
          {
          public:
             virtual void Start(int parameterCount, void *pars);
          protected:
             Thread();
             virtual void run(int parameterCount, void *pars) = 0;
          }
          

          只需确保您的参数以某种方式收缩,例如#1 将是 int,#2 将是 double 等等。:)

          【讨论】:

            猜你喜欢
            • 2012-09-16
            • 2011-08-09
            • 2016-04-16
            • 2021-06-30
            • 2018-09-09
            • 1970-01-01
            • 1970-01-01
            • 2017-03-22
            • 2010-09-07
            相关资源
            最近更新 更多