有一个下载器应用程序,它在多个线程中对下载项目执行不同类型的处理。一些线程分析输入数据,一些执行下载、提取、保存状态等。因此,每种类型的线程都对某些数据成员进行操作,其中一些线程可能同时运行。下载项可以这样描述:
class File;
class Download
{
public:
enum State
{
Parsing, Downloading, Extracting, Repairing, Finished
};
Download(const std::string &filePath): filePath(filePath) { }
void save()
{
// TODO: save data consistently
StateFile f; // state file for this download
// save general download parameters
f << filePath << state << bytesWritten << totalFiles << processedFiles;
// Now we are to save the parameters of the files which belong to this download,
// (!) but assume the downloading thread kicks in, downloads some data and
// changes the state of a file. That causes "bytesWritten", "processedFiles"
// and "state" to be different from what we have just saved.
// When we finally save the state of the files their parameters don't match
// the parameters of the download (state, bytesWritten, processedFiles).
for (File *f : files)
{
// save the file...
}
}
private:
std::string filePath;
std::atomic<State> state = Parsing;
std::atomic<int> bytesWritten = 0;
int totalFiles = 0;
std::atomic<int> processedFiles = 0;
std::mutex fileMutex;
std::vector<File*> files;
};
我想知道如何一致地保存这些数据。例如,状态和已处理文件的数量可能已经保存,我们将保存文件列表。同时其他一些线程可能会改变文件的状态,从而改变处理文件的数量或下载的状态,使保存的数据不一致。
想到的第一个想法是为所有数据成员添加一个互斥锁,并在每次访问它们时锁定它。但这可能是低效的,因为大多数时间线程访问不同的数据成员并且在几分钟内只进行一次保存。
在我看来这样的任务在多线程编程中相当普遍,所以我希望有经验的人能提出更好的方法。