线程在c++中不能将文件复制到队列中



我试图做一个函数,从文件读取信息到队列,然后从队列读取信息到文件的另一个函数。这两个函数都是由线程启用的。问题是,第一个函数没有正确存储信息,我不知道为什么?有人能帮我吗?这是代码:

void MessagesSender::saveMessages()
{
std::string line = "";
std::ifstream file(FILE_TO_READ);
if (file.is_open())
{
while (std::getline(file, line))
{
mutReadToFile.lock();
this->message.push(line);
mutReadToFile.unlock();
}
file.close();
}
else
{
std::cout << "Faild" << std::endl;
}
std::ofstream removeFile(FILE_TO_READ, std::ofstream::out | std::ofstream::trunc); //to delete the file
std::cout << "wait a minute..." << std::endl;
//std::this_thread::sleep_for(std::chrono::seconds(60));

}

和其他功能:

void MessagesSender::sendMessages()
{
std::ofstream file;
std::vector<std::string> connectUsers;
connectUsers = this->getConnectUsers();
file.open(FILE_TO_WRITE, std::ios::app);
if (file.is_open())
{
while (!this->message.empty())
{
for (int i = 0; i < connectUsers.size(); i++)
{
file << connectUsers[i] << ": " << this->message.front() << std::endl;
}
mutReadToFile.lock();
this->message.pop();
mutReadToFile.unlock();
}
file.close();
std::cout << "Copy successfully" << std::endl;
}
else //If the file doesn't open
{
std::cout << "faild :(" << std::endl;;
}

}

这是菜单:

int main()
{
MessagesSender mess;
mess.printMenu();
std::thread read(&MessagesSender::saveMessages, mess);
std::thread write(&MessagesSender::sendMessages, mess);
read.join();
write.join();
system("pause");
return 0;

}

你的线程使用MessagesSender的副本。

std::thread read(&MessagesSender::saveMessages, mess);
std::thread write(&MessagesSender::sendMessages, mess);

这些按值绑定。使用std::ref防止复制mess:

std::thread read(&MessagesSender::saveMessages, std::ref(mess));
std::thread write(&MessagesSender::sendMessages, std::ref(mess));

或者,使用指针:

std::thread read(&MessagesSender::saveMessages, &mess);
std::thread write(&MessagesSender::sendMessages, &mess);

现场演示

像往常一样,让我添加一个现场演示。

  • 展示了如何使用lock_guard或unique_lock来使用异常安全锁定
  • 修复了操作(empty()是一个数据竞争,因为它在锁之外)
  • 使用c++ 11的range for
  • 对文件流进行习惯性错误处理
  • 修复了对截断的误导性评论(没有文件被删除,否则,只是std::remove它?)
  • 为ifstream/ofstream使用RAII而不是手动close()

有"bigger"功能性问题:

  • 我假设您希望所有连接的用户重复消息,而不是每次弹出。
  • 有一个竞争条件。如果sendMessages线程启动得太快,它就会退出,因为队列是空的。这是在您的代码中设计的。我将把这句话留给读者。

我可能忘记了一些

Live On Coliru

#include <fstream>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>
static const std::string FILE_TO_READ = "input.txt";
static const std::string FILE_TO_WRITE = "output.txt";
struct MessagesSender {
std::mutex _queueMutex;
std::vector<std::string> getConnectUsers() {
return { "john", "alice", "bob" };
}
void printMenu() { std::cout << "I don't know what's for dinnern"; }
void sendMessages();
void saveMessages();
std::queue<std::string> _messages;
};
void MessagesSender::saveMessages()
{
std::string line;
{
std::ifstream file(FILE_TO_READ);
while (std::getline(file, line)) {
std::lock_guard lock(_queueMutex);
_messages.push(line);
}
if (!file.good() && !file.eof()) {
std::cout << "Faild" << std::endl;
}
} // closes file
{
std::ofstream removeFile(FILE_TO_READ, std::ios::trunc); // to empty the file
}
std::cout << "Input closed" << std::endl;
}
// and the other function:
void MessagesSender::sendMessages()
{
std::ofstream file(FILE_TO_WRITE, std::ios::app);
if (!file) {
std::cout << "faild :(" << std::endl;
return;
}
auto const connectUsers = MessagesSender::getConnectUsers();
std::unique_lock<std::mutex> lock(_queueMutex);
while (!_messages.empty())
{
auto current = _messages.front();
_messages.pop();
lock.unlock();
for (const auto& user : connectUsers) {
file << user << ": " << current << std::endl;
}
lock.lock();
}
std::cout << "Copy successfully" << std::endl;
}
// this is the menu:
int main()
{
MessagesSender mess;
mess.printMenu();
std::thread read(&MessagesSender::saveMessages, &mess);
std::thread write(&MessagesSender::sendMessages, &mess);
read.join();
write.join();
}

最新更新