编辑:已解决

我现在正在开发一个多线程项目,其中有一个基础工作程序类,具有从中继承的各种工作程序类。在运行时,工作程序类成为线程,然后根据需要执行工作。

现在,我已经编写了一个Director,该Director应该维护一个指向所有 worker 的指针数组,以便它可以从他们那里检索信息,以及以后修改他们内部的变量。

我通过创建一个指向基类指针的指针来做到这一点:

baseWorkerClass** workerPtrArray;

然后,在Director的构造函数中,我为基 worker 类动态分配一个指针数组:
workerPtrArray = new baseWorkerClass*[numWorkers];

在每个工作程序线程的构造函数中,工作程序在Director中调用一个函数,该函数旨在将该工作程序的指针存储在数组中。

导演存储指针的方式如下:
Director::manageWorker(baseWorkerClass* worker)
{
    workerPtrArray[worker->getThreadID()] = worker;
}

这是一个 worker 变量的例子。每个工作程序都继承自基本工作程序类,并且基本工作程序类包含应存在于所有工作程序变量中的纯虚函数,以及一些在所有工作程序之间共享的变量。
class workerVariant : protected baseWorkerClass
{
    public:

    workerVariant(int id)
    : id(id)
    {
        Director::manageWorker(this);
    }

    ~workerVariant()
    {
    }

    int getThreadID()
    {
        return id;
    }

    int getSomeVariable()
    {
        return someVariable;
    }

    protected:

    int id;
    int someVariable
};

然后,baseWorkerClass看起来像这样:
class baseWorkerClass
{
public:

    baseWorkerClass()
    {
    }

    ~baseWorkerClass()
    {
    }

    virtual int getThreadID() = 0;
    virtual int getSomeVariable() = 0;
};

在完成每个worker变量的初始化之后,我应该以指向baseWorkerClass对象的指针数组结尾。这意味着我应该能够例如使用其ID作为数组的索引来获取某个工作程序中给定变量的值,如下所示:
workerPtrArray[5]->getSomeVariable(); // Get someVariable from worker thread 5

问题是该代码导致Windows可执行文件崩溃,而没有任何原因的解释,而在Linux中,它说:



我可能发誓我曾经在某个时候完成过这项工作,所以我对自己搞砸的事情感到困惑。

实际的未修改的代码有问题:

worker 变量 header :http://pastebin.com/f4bb055c8
工作程序变体源文件:http://pastebin.com/f25c9e9e3

基本 worker 类 header :http://pastebin.com/f2effac5
基础 worker 类源文件:http://pastebin.com/f3506095b

导演 header :http://pastebin.com/f6ab1767a
导演源文件:http://pastebin.com/f5f460aae

编辑:额外的信息,在manageWorker函数中,我可以从指针“worker”调用任何纯虚函数,并且工作正常。在manageWorker函数之外,当我尝试使用指针数组时,它失败。

编辑:现在我考虑一下,线程的入口点是operator()。 Director线程是在工作线程之前创建的,这可能意味着重载的括号运算符在调用纯虚函数之前会被子类覆盖。我正在调查这个。

最佳答案

问题似乎是在Director::manageWorker实例的构造函数中调用了workerVariant:

Director::manageWorker(baseWorkerClass* worker) {
    workerPtrArray[worker->getThreadID()] = worker;
}

大概getThreadID()不是纯粹的虚函数,否则(希望!)您将获得一个编译器错误,原因是未在workerVariant中覆盖它。但是getThreadID()可能会调用您应重写的其他函数,但这些函数在抽象类中被调用。您应该仔细检查getThreadID()的定义,以确保在正确初始化子类之前,不要做任何依赖于子类的不良事情。

更好的解决方案可能是将这种多阶段初始化分离为单独的方法,或者设计DirectorbaseWorkerClass以使它们不具有这种初始化时的相互依赖性。

10-07 18:13