webServer设计(一)—— 线程同步类
1 不可复制的类
互斥锁pthread_mutex_t本就不建议通过复制的方式来初始化,而应该在所属线程使用专门的初始化函数进行管理,封装成类之后也应该保证其不被拷贝。
#ifndef BASE_UNCOPYABLE_H
#define BASE_UNCOPYABLE_H
class uncopyable{
public:
//c++11的新机制,确保拷贝构造函数和拷贝复制运算符无效。
uncopyable(const uncopyable&)=delete;
void operator=(const uncopyable&)=delete;
protected:
uncpoyable() {}
~Uncopyable() {}
}
#endif //BASE_UNCOPYABLE_H 2 互斥锁
使用RAII机制来管理互斥锁mutex,通过作用域来管理临界区,实现锁的自动释放。
//Mutex.h
#ifndef BASE_MUTEX_H
#define BASE_MUTEX_H
#include <pthread.h>
#include <assert.h>
#include <uncopyable.h>
//互斥锁,无法被复制。
class MutexLock : uncopyable {
public:
MutexLock()
{
pthread_mutex_init(&mutex_,NULL);
}
~MutexLock()
{
//pthread_mutex_lock(&mutex_);
pthread_mutex_destroy(&mutex_);
}
void lock() { pthread_mutex_lock(&mutex_); }
void unlock() { pthread_mutex_unlock(&mutex_); }
pthread_mutex_t *getMutex(){ //仅供Condition使用。
return &mutex_;
}
private:
pthread_mutex_t mutex_;
private:
friend class Condition;
};
//临界锁,使用后的区域即为临界区。
class MutexLockGuard : uncopyable {
public:
explicit MutexLockGuard(MutexLock& mutex):mutex_(mutex) { mutex_.lock(); } //临界区加锁
~MutexLockGuard(){ mutex_.unlock(); } //临界区解锁
private:
MutexLock &mutex_;
};
#endif //BASE_MUTEX_H
3 条件量
条件量主要用于线程间的同步,一个线程阻塞于wait函数,等待另外一个线程执行并notify()/notifyAll()。
- 用于主线程等待单个子线程完成任务
- 用于多个子线程等待主线程的“起跑”命令
//Condition.h
#ifndef BASE_CONDITION_H
#define BASE_CONDITION_H
#include <pthread.h>
#include <time.h>
#include <cstdint>
#include "Mutex.h"
#include "uncopyable.h"
class Condition : uncopyable {
public:
explicit Condition(MutexLock &mutex):mutex_(mutex) {
pthread_cond_init(&cond_,NULL);
}
~Condition() { pthread_cond_destroy(&cond_); }
void wait() { pthread_cond_wait(&cond_,mutex_.getMutex()); }
void notify() { pthread_cond_signal(&cond_); }
void notifyAll() { pthread_cond_broadcast(&cond_); }
bool waitForSeconds(int seconds) {
struct timespec abstime;
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += static_cast<time_t>(seconds);
return ETIMEDOUT == pthread_cond_timedwait(&cond, mutex.get(), &abstime);
}
private:
MutexLock &mutex_;
pthread_cond_t cond_;
};
#endif //BASE_CONDTION_H 4 倒计时同步
CountDownLatch与Condition的区别主要在于CountDownLatch有一个计数功能,调用cout次countDown之后wait才会停止阻塞。
- 用于主线程等待多个子线程完成初始化;
- 用于多个子线程等待主线程发出“起跑”命令。
//CountDownLatch.h
#ifndef BASE_COUNTDOWNLATCH_H
#define BASE_COUNTDOWNLATCH_H
#include "Condition.h"
#include "MutexLock.h"
#include "uncopyable.h"
class CountDownLatch : uncopyable {
public:
explicit CountDownLatch(int count);
void wait();
void countDown();
private:
mutable MutexLock mutex_;
Condition condition_;
int count_;
};
#endif //CountDownLatch.cpp
#include "CountDownLatch.h"
CountDownLatch::countDownLatch(int count)
:mutex_(),condition(mutex_),count_(count) {}
void CountDownLatch::wait() {
MutexLockGuard lock(mutex_);
while(count_>0) condition_.wait();
}
void CountDownLatch::countDown() {
MutexLockGuard lock(mutex_);
--count_;
if(count_==0) condition_.notifyAll();
} 5 总结
- 互斥锁的主要作用是保证对临界区访问的顺序执行。比如进程间共享的条件量或者计数值。
- 条件量主要是用于线程间的同步,一个(或多个)线程阻塞直到另一线程达成条件。
- 倒计时类与条件量相比多了一个计数功能,能够限定代码的执行次数或者保证多个线程的同步。
- 在webserver的设计中,互斥量主要与条件量结合使用,一个是在线程池中,主线程通过条件量等待子线程函数的执行。

京公网安备 11010502036488号