Существует приложение-загрузчик, которое выполняет различные виды обработки на элементах загрузки в нескольких потоках. Некоторые потоки анализируют входные данные, некоторые выполняют загрузку, извлечение, сохранение состояния и т. Д. Таким образом, каждый тип потока работает с определенными элементами данных, и некоторые из этих потоков могут выполняться одновременно. Загрузить пункт можно описать следующим образом:Сохранение данных при многопоточной обработке
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;
};
Мне интересно, как сохранить эти данные последовательно. Например, состояние и количество обработанных файлов уже были сохранены, и мы собираемся сохранить список файлов. Между тем некоторые другие потоки могут изменять состояние файла и, следовательно, количество обработанных файлов или состояние загрузки, что делает сохраненные данные непоследовательными.
Первой идеей, которая приходит на ум, является добавление одного мьютекса для всех элементов данных и блокировка его каждый раз, когда имеет доступ к любому из них. Но это было бы, вероятно, неэффективно, так как большинство потоков времени обращаются к различным членам данных, а сохранение происходит только один раз за несколько минут.
Мне кажется, что такая задача довольно распространена в многопоточном программировании, поэтому я надеюсь, что опытные люди могут предложить лучший способ.
* "Первая мысль, которая приходит на ум, чтобы добавить один семафор для всех членов данных и блокировать его каждый раз, когда любой из них будет доступен ». * - Почему вы не можете использовать несколько мьютексов и блокировать доступ к отдельным членам? И почему бы не разделить класс на несколько разных классов, чтобы каждый поток мог спокойно работать над своими собственными фрагментами данных до тех пор, пока он не будет закончен, а частичные результаты будут собраны в конечный результат? –
Ну, как я описал выше, блокировка отдельных элементов не препятствует сохранению целого набора данных. Например. сохраненное состояние загрузки и количество обработанных файлов могут не совпадать с сохраненным списком файлов. Ну, потоки могут использовать одни и те же элементы данных. Я просто хотел, чтобы они использовали не все из них. – mentalmushroom