TinywebServer代码详解–线程同步机制封装类(1)

原项目地址(点击跳转)

博主添加注释后项目地址(点击跳转)


一、基础知识

1.RAII

  • RAII全称是“Resource Acquisition is Initialization”,直译过来是“资源获取即初始化”.
  • 在构造函数中申请分配资源,在析构函数中释放资源。因为C++的语言机制保证了,当一个对象创建的时候,自动调用构造函数,当对象超出作用域的时候会自动调用析构函数。所以,在RAII的指导下,我们应该使用类来管理资源,将资源和对象的生命周期绑定
  • RAII的核心思想是将资源或者状态与对象的生命周期绑定,通过C++的语言机制,实现资源和状态的安全管理,智能指针是RAII最好的例子


2.信号量

可以查看之前学习爱编程的大丙,记录的Blog多线程与线程同步(点击跳转)



3.互斥量

可以查看之前学习爱编程的大丙,记录的Blog多线程与线程同步(点击跳转)



4.条件变量

可以查看之前学习爱编程的大丙,记录的Blog多线程与线程同步(点击跳转)




二、代码解析

lock/locker.h代码较为简单

  • 类中主要是Linux下三种锁(互斥量、条件变量、信号量)进行封装,将锁的创建于销毁函数封装在类的构造与析构函数中,实现RAII机制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#pragma once
#include <exception>
#include <pthread.h>
#include <semaphore.h>

// 互斥锁类
class locker{
public:
locker()
{
if(pthread_mutex_init(&m_mutex,NULL)!=0)
{
throw std::exception(); // 互斥锁初始化成功return 0,否则非0,抛出异常
}
}

~locker()
{
pthread_mutex_destroy(&m_mutex);
}

bool lock()
{
return pthread_mutex_lock(&m_mutex) == 0; // return 0表示加锁成功
}

bool unlock()
{
return pthread_mutex_unlock(&m_mutex) == 0;
}

pthread_mutex_t *get()
{
return &m_mutex;
}

private:
// 定义一个私有的互斥锁变量
pthread_mutex_t m_mutex;
};


// 条件变量类
class cond{
public:
cond()
{
if(pthread_cond_init(&m_cond,NULL) != 0)
{
throw std::exception(); // 条件变量初始化成功return 0
}
}

~cond()
{
pthread_cond_destroy(&m_cond);
}

bool wait(pthread_mutex_t *m_mutex)
{
int ret = 0;
ret = pthread_cond_wait(&m_cond,m_mutex); // 线程阻塞函数
return ret==0;
}

// 设置阻塞时间
bool timeWait(pthread_mutex_t *m_mutex,struct timespec t)
{
int ret = 0;
ret = pthread_cond_timedwait(&m_cond,m_mutex,&t); // 设置了阻塞时间的线程阻塞函数
return ret ==0;
}

// 唤醒单个阻塞线程
bool signal()
{
return pthread_cond_signal(&m_cond) == 0; // 唤醒阻塞在线程阻塞函数上的单个线程
}

// 广播唤醒所有阻塞线程
bool broadcast()
{
return pthread_cond_broadcast(&m_cond) == 0; // 唤醒阻塞在线程阻塞函数上的所有线程
}
private:
pthread_cond_t m_cond;
};


// 信号量类
class sem{
public:
sem()
{
// 参数3,设置的信号量为0
if(sem_init(&m_sem,0,0) != 0)
{
throw std::exception();
}
}

sem(int num){
if(sem_init(&m_sem,0,num) != 0)
{
throw std::exception();
}
}

~sem()
{
sem_destroy(&m_sem);
}

// 等待信号量
bool wait()
{
// 信号量,m_sem不为0,则sem_wait return 0
// 信号量,m_sem为0,则sem_wait 阻塞线程
return sem_wait(&m_sem) == 0;
}

// 增加信号量
bool post()
{
// 增加信号量,并且唤醒一个阻塞在sem_wait() 上的线程
return sem_post(&m_sem) == 0;
}
private:
sem_t m_sem;
};