实现文件写入的互斥锁

时间:2018-03-07 15:23:39

标签: c++ c multithreading synchronization mutex

我正在尝试使用互斥锁来避免多次写入C / Cpp中的同一个线程。以下是我的程序流程。我很困惑在哪里包括我的锁和解锁代码。

main() {
    spawn a worker thread
}
worker_thread() {
    read the input file name 
    read some content
    write the content to the given file name
}

我看到的大部分实现似乎都有类似的内容:

main() {
    pthread_mutex_init(&myMutex;,0);
    *spawn a worker thread*
    pthread_join(thread1, 0);
    pthread_mutex_destroy(&myMutex;);
}
worker_thread() {
    read the input file name 
    read some content
    write the content to the given file name
}

我想要的是这样的东西:

main() {
    spawn a worker thread
}
worker_thread() {
    read the input file name 
    read some content
    pthread_mutex_init(&myMutex;,0) --> for the given file?
    write the content to the given file name
    pthread_mutex_destroy(&myMutex;);
}

任何想要继续欣赏的想法。谢谢!

1 个答案:

答案 0 :(得分:0)

为iostream创建包装器相当容易,确保一次只能有一个线程写入流。不幸的是,几乎一旦你这样做,你就会遇到另一个问题。它确保一次只能有一个线程插入到流中,因此您可以获得已定义的行为。但是,如果你有类似的东西:

主题1:sync_stream << a << b << c << '\n';
主题2:sync_stream << x << y << z << '\n';

你想要的是:

  

ABC
  XYZ

...或者:

  

XYZ
  ABC

由于它们处于不同的线程中,因此它们之间的顺序变化很好,但是一个线程的输出线应保持单行输出。类似的东西:

  

ABXY
  CZ

......可能不是可取的或可接受的。为了避免这种情况,我们确实需要两个单独的类。一个是同步流。另一个是让我们在流中做一些(或多或少随意)插入作为单个不可分割的&#34;事务&#34;。为此,我们可以使用这样的一对类:

class transaction {
    std::ostringstream buffer;
public:
    transaction(std::string const &s="") : buffer(s, std::ios::out | std::ios::ate) {}

    template <class T>
    transaction &operator<<(T const &t) {
        buffer << t;
        return *this;
    }

    friend std::ostream &operator<<(std::ostream &os, transaction const &t) {
        return os << t.buffer.str();
    }
};

class sync_stream {
    std::ostream &out;
    std::mutex mutex;
public:
    sync_stream(std::ostream &sink) : out(sink) { }

    void operator<<(transaction const &t) {
        std::lock_guard<std::mutex> l(mutex);
        out << t;
    }    
};

请注意,transaction类支持链接,但sync_stream不支持(并且您可以插入的唯一内容是transaction)。要使用它们,我们会这样做:

for (int i=0; i<10; i++)
    threads[i] = std::thread([&]{ 
        for (int i=0; i<10; i++) 
            s << (transaction() << "Thread: " << std::this_thread::get_id() << "\n");
    });

这样,一个线程认为单个输出实际上是单个输出,所以我们的结果可能如下所示:

  

主题:140375947724544
  线程:140376068564736
  线程:140375964509952
  线程:140375964509952
  线程:140375972902656
  线程:140375964509952

当然,你会获得与我不同的线程ID,并且线条的顺序可能会有所不同 - 但每一行都将被写为一个完整的单位。

摘要

工作线程根本不应该直接与互斥锁一起工作。这应该是自动化的,因此工作者线程可以专注于其工作,并且只花费最少的努力来完成其工作所需的基础机制。