0

我正在做一个学校项目,但在我的课程中使用线程时遇到了麻烦。我有一个类(下载),它有一个线程,atomic<bool>当线程完成工作时将指针设置为 true,另一个类在自己的线程上运行,当该类看到下载的状态已完成时,它应该删除它从它的列表中。像现在这样设置类后,我指向的任何指针上的任何存储都atomic<bool>将仅更新最近创建的对象,以便仅将列表的末尾设置为完成。这是代码...

class Download
{
private:
    Show *showPtr;
    int season;
    int episode;
    int downloadTime;
    atomic<bool> complete;
    thread downloadThread;
    // Edit: Hans Passant's solution to compiler error problems -
    Download(const Download&);
    Download& operator=(const Download&);
public:
    Download(Show * showPtr);
    string status(bool &complete);
    bool operator==(const Download &other) const;
    friend void blockThenSetComplete(Download *dl);
};


Download::Download(Show * showPtr)
    : showPtr(showPtr)
{
    complete.store(false);
    // Randomly pick a download time from 20 - 30 seconds.
    downloadTime = rand() % 11 + 20;
    // Track which episode this thread is downloading.
    season = showPtr->getNumberDownloaded() / showPtr->getNumberOfEpisodesPerSeason() + 1;
    episode = showPtr->getNumberDownloaded() - showPtr->getNumberOfEpisodesPerSeason() * (season - 1) + 1;
    showPtr->incrementDownloaded();
    // Download the episode and return control.
    downloadThread = thread(blockThenSetComplete, this);
}

string Download::status(bool & complete)
{
    complete = this->complete.load();
    stringstream ss;
    ss << showPtr->getTitle() << " S" << season << "E" << episode;
    return ss.str();
}

void blockThenSetComplete(Download *dl)
{
    this_thread::sleep_for(chrono::seconds(dl->downloadTime));
    dl->complete.store(true);
}

bool Download::operator==(const Download &other) const
{
    if (other.showPtr == showPtr &&
        other.season == season &&
        other.episode == episode)
        return true;
    else
        return false;
}

还有下载管理器...

// Ran as a thread, will fire up or tear down downloads as appropriate.
void downloadManager(Model *model)
{
    while(true)
    {
        bool callNotify = false;
        // monitoring shows
        if (model->shows.size() != 0)
        {
            // connections available
            if (model->account.getTotalConnectionCount() > model->account.getTotalActiveCount())
            {
                // check each show
                for (list<Show>::iterator showIt = model->shows.begin(); showIt != model->shows.end(); showIt++)
                {
                    // find a show that needs a download
                    if (~((*showIt).allDownloading()))
                    {
                        // must check connections again
                        if (model->account.getTotalConnectionCount() > model->account.getTotalActiveCount())
                        {
                            // Reserve connection and add to list.
                            model->account.reserveConnection();
                            model->downloads.push_back(Download(&(*showIt)));
                            callNotify = true;
                        }
                    }
                }
            }
        }
        // monitoring downloads
        if (model->downloads.size() != 0)
        {
            // check each download
            for (list<Download>::iterator downIt = model->downloads.begin(); downIt != model->downloads.end(); downIt++)
            {
                // find a finished download
                bool finished = false;
                (*downIt).status(finished);
                if (finished)
                {
                    // Remove from list, release connection, break as iterators are now invalid
                    model->downloads.remove(*downIt);
                    model->account.releaseConnection();
                    callNotify = true;
                    break;
                }
            }
        }

        if (callNotify)
            model->notify();
        // Check periodically.
        this_thread::sleep_for(chrono::seconds(10));
    }
}

我知道指针没有析构函数,它在线程因某种原因被启动并让程序保释后立即被调用。我使用指针的原因是我似乎无法将线程或原子作为数据成员。现在这可能是我问题的真正根源。如果我通过并更改指向这些类的实例的指针,我会收到以下错误:

Error   3   error C2248: 'std::atomic<bool>::atomic' : cannot access private member declared in class 'std::atomic<bool>'   e:\users\robert\documents\visual studio 2012\projects\pvrsim\pvrsim\download.h  36  1   PVRsim
Error   4   error C2248: 'std::thread::thread' : cannot access private member declared in class 'std::thread'   e:\users\robert\documents\visual studio 2012\projects\pvrsim\pvrsim\download.h  36  1   PVRsim

任何有更多经验的人能够找出我做错了什么?

4

1 回答 1

1

值得看一下 std::thread 和 std::atomic 类的定义,看看它到底在抱怨什么私有成员。例如,当您查看 vc/include/thr/thread 头文件时,您会看到:

private:
    thrd_t _Thr;
    bool _Joinable;
    friend class thread_group;

    thread(const thread&);  // not defined
    thread& operator=(const thread&);       // not defined

注意后两个成员,分别是复制构造函数和赋值运算符。注意// not defined评论。

这是 C++ 中一个非常标准的技巧,用于防止客户端代码复制类的对象。这对于 std::thread 来说相当重要,没有复制线程可以工作的场景。与线程相关的运行时状态太多了,它有自己的堆栈和自己的执行状态。你永远无法复制它。或者使那个有用的模 Unix'fork()。

这个问题中难以猜测的部分是为什么编译器试图使用复制构造函数。这是在您看不到的代码中完成的。当您不声明自己的复制构造函数和赋值运算符时,C++ 编译器将为您创建一个。这将调用您的成员类的相应成员。哪些被声明为private,因此编译错误。

所以你需要做的是防止你自己的类也被复制。这是正确的,创建您的 Download 类对象的副本是没有意义的。您使用与std::thread完全相同的技术来执行此操作,将您的复制构造函数和赋值运算符设为私有并且不定义它们。使固定:

private:
    Download(const Downoad&);              // not defined
    Download& operator=(const Download&);  // not defined

编译器现在将不再尝试生成这些成员的自己的版本,问题解决了。

于 2013-05-27T08:51:31.037 回答