【问题标题】:std::lock_guard with variadic templates带有可变参数模板的 std::lock_guard
【发布时间】:2019-03-05 22:55:07
【问题描述】:

[不必通过链接来理解问题]。

我结合了this answer中单例模式的实现,以及this other answer的同步文件写入。

然后我想看看SynchronizedFile的接口是否可以提供一个可变参数模板write方法,但是我不知道如何将它与std::lock_guard正确结合。

下面是一个不工作的例子。在这种情况下,它不起作用,因为(我认为)两个线程设法以非同步方式将内容泵入缓冲区i_buf,从而导致LOGFILE.txt 出现乱码。

如果我将std::lock_guard 放在write 的通用模板中,则程序不会停止。

#include <iostream>
#include <mutex>
#include <sstream>
#include <fstream>
#include <string>
#include <memory>
#include <thread>

static const int N_LOOP_LENGTH{10};

// This class manages a log file and provides write method(s)
// that allow passing a variable number of parameters of different
// types to be written to the file in a line and separated by commas.
class SynchronizedFile {
public:
    static SynchronizedFile& getInstance()
    {
        static SynchronizedFile instance;
        return instance;
    }

private:
    std::ostringstream i_buf;
    std::ofstream i_fout;
    std::mutex _writerMutex;

    SynchronizedFile () {
        i_fout.open("LOGFILE.txt", std::ofstream::out);
    }

public:
    SynchronizedFile(SynchronizedFile const&) = delete;
    void operator=(SynchronizedFile const&)   = delete;

    template<typename First, typename... Rest>
    void write(First param1, Rest...param)
    {
        i_buf << param1 << ", ";
        write(param...);
    }

    void write()
    {
        std::lock_guard<std::mutex> lock(_writerMutex);
        i_fout << i_buf.str() << std::endl;
        i_buf.str("");
        i_buf.clear();
    }
};

// This is just some class that is using the SynchronizedFile class
// to write stuff to the log file.
class Writer {
public:
    Writer (SynchronizedFile& sf, const std::string& prefix) 
        : syncedFile(sf), prefix(prefix) {}

    void someFunctionThatWritesToFile () {
        syncedFile.write(prefix, "AAAAA", 4343, "BBBBB", 0.2345435, "GGGGGG");
    }
private:
    SynchronizedFile& syncedFile;
    std::string prefix;
};

void thread_method()
{
  SynchronizedFile &my_file1 = SynchronizedFile::getInstance();
  Writer writer1(my_file1, "Writer 1:");
  for (int i = 0; i < N_LOOP_LENGTH; ++ i)
    writer1.someFunctionThatWritesToFile();
}

int main()
{
  std::thread t(thread_method);

  SynchronizedFile &my_file2 = SynchronizedFile::getInstance();
  Writer writer2(my_file2, "Writer 2:");
  for (int i = 0; i < N_LOOP_LENGTH; ++i)
    writer2.someFunctionThatWritesToFile();

  t.join();
  std::cout << "Done" << std::endl;
  return 0;
}

我怎样才能成功地结合这三个想法?

【问题讨论】:

    标签: c++ thread-safety variadic-templates


    【解决方案1】:

    程序死锁是因为write 在仍持有锁的同时递归调用自身。

    要么使用std::recursive_mutex,要么在写出数据之后但在调用write之前释放锁。 E: 解锁不行,我没想到这个……

    E:或者锁定一次,然后使用另一个私有方法进行写入。

    template<typename... Args>
    void write(Args&&... args)
    {
        std::unique_lock<std::mutex> lock(_writerMutex);
        _write(std::forward<Args>(args)...);
    }
    
    template<typename First, typename... Rest>
    void _write(First&& param1, Rest&&... param) // private method
    {
        i_buf << std::forward<First>(param1) << ", ";
        _write(std::forward<Rest>(param)...);
    }
    
    void _write()
    {
        i_fout << i_buf.str() << std::endl;
        i_buf.clear();
    }
    

    【讨论】:

    • 让我研究一下 recursive_mutex (我显然是使用线程的新手)。我不明白您在第二种选择中所指的职位。你已经回答过了。
    • @user647486 我添加了一个示例。对于std::recursive_mutexunlock 不是必需的。
    • 其中一些想法可能会帮助我解决问题。但是,让我告诉你,unique_lock 的第一个似乎没有。我认为这是因为std::endl 位于未“锁定”的部分。文件中的某些行被串联打印或在几个换行符之后打印。让我试试recursive_mutex 方法。
    • recursive_mutex 方法确实可以正常工作。谢谢你。我不知道。
    猜你喜欢
    • 2022-01-05
    • 2014-09-08
    • 1970-01-01
    • 2016-06-11
    • 2018-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多