无法将文件复制到 C++ 队列中的线程

threads that not working to copy a file into queue in 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 范围
  • 使文件流的错误处理变得地道
  • 修复关于截断的误导性评论(没有文件被删除,否则,只是 std::remove 吗?)
  • 对 ifstream/ofstream 使用 RAII 而不是手动关闭 ()

存在“更大”的功能问题:

  • 我假设您希望为所有连接的用户重复发送消息,而不是每次都弹出消息。
  • 存在竞争条件。如果您的 sendMessages 线程启动得太早,它将因为队列为空而退出。这是在您的代码中设计的。我会把它留作 reader.
  • 的驱魔

我可能忘记了一些

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 dinner\n"; }
    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();
}