========》Linux | Linux中的线程、互斥量、信号量的基本使用《========
信号量是一个计数器,用于限制并发访问共享资源的线程数;此计数器始终介于 0 和信号量创建期间指定的最大值之间;
- 当计数器严格大于0时,对Wait()的调用立即返回并递减计数器;
- 一旦达到0,对Wait的任何后续调用都会阻塞,并且仅在信号量计数器再次变为严格正数时返回,因为调用Post()会增加计数器;
通常,信号量可用于限制对共享资源的访问,该共享资源只能由某些固定数量的客户端同时访问;
例如,在对酒店预订系统建模时,可以创建计数器等于可用房间总数的信号量。每次预留房间时,应通过调用Wait()获取信号量,每次释放房间时应通过调用Post释放信号量;
C++11 和 Boost.Thread 都没有提供信号量:
信号量因太容易出错而被删除。通过互斥体和条件变量的组合可以更安全地实现相同的效果;Dijkstra(信号量的发明者)、
Hoare 和 Brinch Hansen 都贬低了信号量并提倡更结构化的替代方案。在 1969 年给 Brinch Hansen 的一封信中,Wirth 说“信号
量……不适合高级语言。” [Andrews-83] 将典型错误总结为“省略P或V ,或在一个信号量上不小心将P和V编码在另一个信号量
上”,忘记在临界区中包含对共享对象的所有引用,以及由于使用“条件同步和互斥”的相同原语;
故以下我们将使用条件变量和互斥量来替代信号量
/** 封装条件变量 */
class Cond {
public:
Cond();
void wait(pthread_mutex_t mutex);
void signal();
~Cond();
private:
pthread_cond_t m_cond;
};
/** 信号量封装使用条件变量和锁 */
class OwnSemaphore : Noncopyable {
public:
typedef Mutex MutexType;
OwnSemaphore(size_t count=0);
~OwnSemaphore();
void wait();
void notify();
size_t getCount() const { return m_count; }
void reset() { m_count = 0;}
private:
size_t m_count;
MutexType m_mutex;
Cond m_cond;
};
OwnSemaphore::OwnSemaphore(size_t count)
:m_count(count){
}
OwnSemaphore::~OwnSemaphore() {
}
void OwnSemaphore::wait() {
MutexType::Lock lock(m_mutex);
while (m_count == 0) {
m_cond.wait(m_mutex.getMutex());
}
--m_count;
}
void OwnSemaphore::notify() {
m_count++;
m_cond.signal();
}
每个工作线程先等待信号量,然后输出线程 ID 和当前时间,输出操作以互斥锁同步以防止错位,睡眠一秒是为了模拟线程处理数
据的耗时。
sylar::OwnSemaphore g_sem(3);
void Worker() {
g_sem.wait();
std::thread::id thread_id = std::this_thread::get_id();
/* 获取时间 */
struct tm tm;
time_t t = time(0);
localtime_r(&t, &tm);
char buf[64];
strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
{
sylar::Mutex::Lock lock(sylar::Mutex);
std::cout << "Thread " << thread_id << ": wait succeeded" << " (" << buf << ")" << std::endl;
}
// Sleep 1 second to simulate data processing.
std::this_thread::sleep_for(std::chrono::seconds(1));
g_sem.notify();
}
int main() {
const std::size_t SIZE = 3;
std::vector<std::thread> v;
v.reserve(SIZE);
for (std::size_t i = 0; i < SIZE; ++i) {
v.emplace_back(&Worker);
}
for (std::thread& t : v) {
t.join();
}
return 0;
}
测试结果
参考文章
https://segmentfault.com/a/1190000006818772