在C++環境下面, 要實現多線程併發, 提升性能, 並不是一件很容易的事情。 難點不是如何劃分出多個線程, 而是如何確認哪些內存是線程間公用的, 需要避免衝突, 另一個方面, 如何做到線程間同步。
線程私有數據
在一個線程裏面, 線程ID和堆棧上的數據, 以及信號集等是線程私有的, 我們還可以通過一些函數指定線程的私有數據, 比如pthread_setspecific。
線程之間通信
線程之間的通信方式, 常見的有2種:信號通知以及管道通知。
信號通知
通常會有信號的產生端和消費端, 信號的產生端通常是有一個隊列, 每當有新的信號產生, 就加入到信號裏面, 消費端通常是一個後臺線程, 每當收到通知, 信號隊列非空, 就會暫時鎖定隊列, 並且將隊列的內容swap到新的隊列, 解鎖之後, 就可以逐個遍歷,處理每個信號。
信號產生端:
class Producer {
std::list<Item*> queue;
void AddItem(Item* item) {
pthread_lock(&mutex);
queue.push_back(item);
pthread_cond_signal(&cond);
pthread_unloc(&mutex);
}
}
信號消費端:
class Consumer {
public:
void process() {
pthread_mutex_lock();
while (1) {
std::list<Item*> queuetmp;
if (!queue.empty()) {
queuetmp.swap(queue);
}
pthread_mutex_unlock();
while (!queuetmp.empty()) {
Item* item = queuetmp.front();
queuetmp.pop_front();
handler(item);
}
pthread_mutex_lock();
pthread_cond_wait(&cond);
}
}
}
管道通知
管道是使用非常廣泛的一種消息通知機制, 可以用於線程間或者進程間通信。pipe函數會產生2個文件描述符,通過pipe函數創建的這兩個文件描述符 fd[0] 和 fd[1] 分別構成管道的兩端,往 fd[1] 寫入的數據可以從 fd[0] 讀出。並且 fd[1] 一端只能進行寫操作,fd[0] 一端只能進行讀操作,不能反過來使用。要實現雙向數據傳輸,可以使用兩個管道。
信號產生端:
class Producer {
std::list<Item*> queue;
int wrfd;
void AddItem(Item* item) {
pthread_lock(&mutex);
queue.push_back(item);
pthread_unloc(&mutex);
// write message to pipe to notify consumer part
write(wrfd, data, size);
}
}
信號消費端:
class Consumer {
private:
int rdfd;
public:
void process() {
// pipe data reader part, using read blocking-mode,
// only when producer part has data written, it will go to
// the while range
while (read(rdfd, buf, size) > 0) {
pthread_mutex_lock();
std::list<Item*> queuetmp;
if (!queue.empty()) {
queuetmp.swap(queue);
}
pthread_mutex_unlock();
while (!queuetmp.empty()) {
Item* item = queuetmp.front();
queuetmp.pop_front();
handler(item);
}
}
}
}