我正在开展一个学校项目,但我在使用线程处理线程时遇到了麻烦。我有一个类(下载),它有一个线程,当线程完成工作时设置一个指向atomic<bool>
的指针,另一个在自己的线程上运行的类,当它看到一个下载状态时是完成后,应将其从列表中删除。在现在设置类的情况下,任何指向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
有经验的人能够找出我做错的事吗?
答案 0 :(得分: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来说非常重要,没有任何情况下复制线程可以工作。 way 与线程关联的运行时状态太多,它有自己的堆栈和自己的执行状态。你无法复制它。或者制作有用的模块Unix'fork()。
这个难以猜测的问题部分是为什么编译器试图使用复制构造函数。这是在你看不到的代码中完成的。当您没有声明自己的复制构造函数和赋值运算符时,C ++编译器将为您创建一个。这将调用您的成员类的相应成员。其中声明私有,因此编译错误。
因此,您需要做的是阻止您的自己的类被复制。哪个是正确的,创建Download类对象的副本没有意义。您可以使用std :: thread使用的 exact 相同的技术,将您的复制构造函数和赋值运算符设为私有,而不是定义它们。修正:
private:
Download(const Downoad&); // not defined
Download& operator=(const Download&); // not defined
编译器现在不再尝试生成这些成员自己的版本,问题解决了。