@@ -21,6 +21,7 @@ class block_queue
2121 {
2222 if (max_size <= 0 )
2323 {
24+ std::cerr << " Fatal Error: block_queue init (max_size <= 0)" << std::endl;
2425 exit (-1 );
2526 }
2627
@@ -29,6 +30,7 @@ class block_queue
2930 m_size = 0 ;
3031 m_front = -1 ;
3132 m_back = -1 ;
33+ m_close = false ;
3234 }
3335
3436 void clear ()
@@ -40,14 +42,17 @@ class block_queue
4042 m_mutex.unlock ();
4143 }
4244
43- ~block_queue ()
44- {
45+ ~block_queue () {
4546 m_mutex.lock ();
46- if (m_array != NULL )
47+ m_close = true ;
48+ m_cond.broadcast (); // 强行叫醒所有还在睡觉的 pop 线程
49+ if (m_array != NULL ){
4750 delete [] m_array;
48-
51+ m_array = NULL ;
52+ }
4953 m_mutex.unlock ();
5054 }
55+
5156 // 判断队列是否满了
5257 bool full ()
5358 {
@@ -77,20 +82,24 @@ class block_queue
7782 bool front (T &value)
7883 {
7984 m_mutex.lock ();
80- if (0 == m_size)
85+ // check: 如果队列已关闭或为空,直接返回
86+ if (m_close || 0 == m_size)
8187 {
8288 m_mutex.unlock ();
8389 return false ;
8490 }
85- value = m_array[m_front];
91+ // 求队首元素索引
92+ int index = ( m_front +1 ) % m_max_size;
93+ value = m_array[index];
8694 m_mutex.unlock ();
8795 return true ;
8896 }
8997 // 返回队尾元素
9098 bool back (T &value)
9199 {
92100 m_mutex.lock ();
93- if (0 == m_size)
101+ // check: 如果队列已关闭或为空,直接返回
102+ if (m_close || 0 == m_size)
94103 {
95104 m_mutex.unlock ();
96105 return false ;
@@ -128,6 +137,13 @@ class block_queue
128137 {
129138
130139 m_mutex.lock ();
140+
141+ // check: 如果队列已关闭,直接返回
142+ if (m_close) {
143+ m_mutex.unlock ();
144+ return false ;
145+ }
146+
131147 if (m_size >= m_max_size)
132148 {
133149
@@ -141,7 +157,7 @@ class block_queue
141157
142158 m_size++;
143159
144- m_cond.broadcast ();
160+ m_cond.signal (); // 减少唤醒多个线程带来的可能额外性能损耗
145161 m_mutex.unlock ();
146162 return true ;
147163 }
@@ -151,15 +167,26 @@ class block_queue
151167
152168 m_mutex.lock ();
153169 while (m_size <= 0 )
154- {
155-
170+ {
171+ // check: 直接退出返回
172+ if (m_close) {
173+ m_mutex.unlock ();
174+ return false ;
175+ }
176+
156177 if (!m_cond.wait (m_mutex.get ()))
157178 {
158179 m_mutex.unlock ();
159180 return false ;
160181 }
161182 }
162183
184+ // check:从 wait 醒来后,可能资源已被析构,必须再次判断
185+ if (m_close) {
186+ m_mutex.unlock ();
187+ return false ;
188+ }
189+
163190 m_front = (m_front + 1 ) % m_max_size;
164191 item = m_array[m_front];
165192 m_size--;
@@ -173,20 +200,29 @@ class block_queue
173200 struct timespec t = {0 , 0 };
174201 struct timeval now = {0 , 0 };
175202 gettimeofday (&now, NULL );
203+
204+ long long total_ns = (now.tv_usec * 1000LL ) + ((ms_timeout % 1000 ) * 1000000LL );
205+ t.tv_sec = now.tv_sec + (ms_timeout / 1000 ) + (total_ns / 1000000000LL );
206+ t.tv_nsec = total_ns % 1000000000LL ;
207+
176208 m_mutex.lock ();
177- if (m_size <= 0 )
178- {
179- t.tv_sec = now.tv_sec + ms_timeout / 1000 ;
180- t.tv_nsec = (ms_timeout % 1000 ) * 1000 ;
181- if (!m_cond.timewait (m_mutex.get (), t))
182- {
209+
210+ // 用 while 对抗虚假唤醒
211+ while (m_size <= 0 ) {
212+ // check: 直接退出返回
213+ if (m_close) {
183214 m_mutex.unlock ();
184215 return false ;
185216 }
217+ // timewait 内部是用绝对时间比较的,所以 t 算好一次就可以一直用
218+ if (!m_cond.timewait (m_mutex.get (), t)) {
219+ m_mutex.unlock ();
220+ return false ; // 真正超时
221+ }
186222 }
187-
188- if (m_size <= 0 )
189- {
223+
224+ // check:从 timewait 醒来后,可能资源已被析构,必须再次判断
225+ if (m_close) {
190226 m_mutex.unlock ();
191227 return false ;
192228 }
@@ -207,6 +243,7 @@ class block_queue
207243 int m_max_size;
208244 int m_front;
209245 int m_back;
246+ bool m_close;
210247};
211248
212249#endif
0 commit comments