【发布时间】:2010-10-16 20:14:57
【问题描述】:
我正在使用一个 C++ 类库,它提供了一个线程基类,用户必须在其中
实现一个run() 方法。
关于如何将参数传递给run() 方法,是否有推荐的方法?现在
我更喜欢通过构造函数(作为指针)传递它们。
【问题讨论】:
标签: c++ multithreading concurrency
我正在使用一个 C++ 类库,它提供了一个线程基类,用户必须在其中
实现一个run() 方法。
关于如何将参数传递给run() 方法,是否有推荐的方法?现在
我更喜欢通过构造函数(作为指针)传递它们。
【问题讨论】:
标签: c++ multithreading concurrency
我不确定 C++,但这就是你在 Java 中的做法。您将拥有一个扩展 Thread(或实现 Runnable)的类和一个带有您想要传递的参数的构造函数。然后,当您创建新线程时,您必须传入参数,然后启动线程,如下所示:
Thread t = new MyThread(args...);
t.start();
在您的情况下必须相同。
【讨论】:
另一种方法是扩展此 Thread 类以接受函子作为唯一的构造函数参数,以便您可以在其中绑定任何调用。
那么使用线程的类就不需要从 Thread 继承,而只有一个(或多个)Thread 成员。仿函数调用你想要的任何起点(带有任何参数的类的某些方法)
【讨论】:
这是一个典型的模式:
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;
}
【讨论】:
线程启动的一个常见问题是传递的参数只存在于调用函数的堆栈上。线程启动通常会被延迟,这样调用函数就会返回,并且仅在一段时间后线程才会真正启动 - 到那时参数不再存在。
对此的一种解决方案是创建一个事件,然后启动线程,将该事件作为参数之一传递。启动函数然后等待事件,该事件由线程在完成启动时发出信号。
【讨论】:
您可以将参数作为线程类的成员传递。创建线程的线程大概可以在线程启动之前调用其他方法和/或调用成员函数。因此,它可以填充它工作所需的任何成员。然后当 run 方法被调用时,它就会有启动所需的信息。
我假设您将为每个线程使用一个单独的对象。
您通常会将您创建的所有线程放入数组、向量等中。
【讨论】:
可以通过构造函数传递它们。只要确保指针的寿命比线程长。
【讨论】:
好吧,我宁愿把参数放在 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 等等。:)
【讨论】: