1. 程式人生 > >多執行緒基礎(單讀、單寫、迴圈佇列、無鎖、lockfree)

多執行緒基礎(單讀、單寫、迴圈佇列、無鎖、lockfree)

有了前面執行緒建立迴圈佇列的基礎,我們再來看一個單度、單寫利用迴圈佇列的例子,程式碼如下:

#include <stdio.h>
#include <pthread.h>
#include <string>
#include "circular_queue.h"
class ThreadBase {
 public:
  virtual ~ThreadBase() {}
  void SetMessage(const char* message) {
    message_ = message;
  }
  void Start() {
    pthread_create(&thread_id_, NULL, Hook, this);
  }
  void* Join() {
    void* ret = NULL;
    pthread_join(thread_id_, &ret);
    return ret;
  }
  virtual void Run() {
    printf("%s\n", message_.c_str());
  }
 private:
  static void* Hook(void* object) {
    ThreadBase* thread_base= static_cast<ThreadBase*>(object);
    thread_base->Run();
  }
  pthread_t thread_id_;
  std::string message_;
};
class ThreadReader : public ThreadBase {
 public:
  ThreadReader(CircularQueue<int>* queue) : queue_(queue), write_finish_(false) {}
  virtual void Run() {
    int element;
    while (!write_finish_) {
      if (queue_->Pop(&element)) {
        printf("read:%d\n",element);
      }
    }
    while (queue_->Pop(&element)) {
      printf("read:%d\n", element);
    }
  }
  void NotifyWriteFinish() {
    write_finish_ = true;
  }
 private:
  CircularQueue<int>* queue_;
  bool write_finish_;
};

class ThreadWriter : public ThreadBase {
 public:
  ThreadWriter(CircularQueue<int>* queue, ThreadReader* reader) : queue_(queue), reader_(reader) {}
  virtual void Run() {
    int index = 0;
    while(index < 10000) {
      if (queue_->Push(index)) {
        index++;
      }
    }
    reader_->NotifyWriteFinish();
  }
 private:
  CircularQueue<int>* queue_;
  ThreadReader* reader_;
};
int main(int argc, char** argv) {
  CircularQueue<int> queue(100);
  ThreadReader reader(&queue);
  ThreadWriter writer(&queue, &reader);
  reader.Start();
  writer.Start();
  reader.Join();
  writer.Join();
}

寫執行緒不間斷寫入資料,寫入完成後會通知讀執行緒已經寫完,讀執行緒持續讀取資料,如果得到通知後,將緩衝區中的資料再全部讀出後,退出。

參考文獻:

《程式設計之美》中1.10 雙執行緒高效下載,但程式設計之美中使用了semaphore,本例子不需要使用semaphore,效率更好。

《系統程式設計師成長計劃》4.5無鎖資料結構