Skip to content

Commit 5952505

Browse files
committed
feat: add thread init and destroy callbacks to TC_ThreadPool
1 parent b981f8e commit 5952505

3 files changed

Lines changed: 271 additions & 9 deletions

File tree

unit-test/util/test_tc_thread_pool.cpp

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,118 @@ TEST_F(UtilThreadPollTest, testDecontructor)
5555
}
5656

5757
tpool.stop();
58+
}
59+
60+
TEST_F(UtilThreadPollTest, testThreadCallbacks)
61+
{
62+
std::atomic<int> initCount(0);
63+
std::atomic<int> destroyCount(0);
64+
65+
TC_ThreadPool pool;
66+
pool.init(4);
67+
68+
pool.setThreadInitCallback([&initCount](){
69+
initCount++;
70+
});
71+
72+
pool.setThreadDestroyCallback([&destroyCount](){
73+
destroyCount++;
74+
});
75+
76+
pool.start();
77+
78+
// 执行一些任务
79+
for (int i = 0; i < 10; ++i)
80+
{
81+
pool.exec([](){
82+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
83+
});
84+
}
85+
86+
pool.waitForAllDone();
87+
pool.stop();
88+
89+
// 验证回调被调用了正确的次数
90+
EXPECT_EQ(initCount.load(), 4);
91+
EXPECT_EQ(destroyCount.load(), 4);
92+
}
93+
94+
TEST_F(UtilThreadPollTest, testThreadLocalStorage)
95+
{
96+
std::mutex mtx;
97+
std::set<int> values;
98+
99+
TC_ThreadPool pool;
100+
pool.init(4);
101+
102+
pool.setThreadInitCallback([](){
103+
static std::atomic<int> counter(1000);
104+
thread_local int g_value = 0;
105+
g_value = counter.fetch_add(1);
106+
});
107+
108+
pool.start();
109+
110+
for (int i = 0; i < 100; ++i)
111+
{
112+
pool.exec([&mtx, &values](){
113+
static thread_local int g_value = 0;
114+
std::lock_guard<std::mutex> lock(mtx);
115+
if (g_value != 0) {
116+
values.insert(g_value);
117+
}
118+
});
119+
}
120+
121+
pool.waitForAllDone();
122+
pool.stop();
123+
}
124+
125+
TEST_F(UtilThreadPollTest, testCallbackException)
126+
{
127+
std::atomic<int> taskCount(0);
128+
129+
TC_ThreadPool pool;
130+
pool.init(2);
131+
132+
// 初始化回调抛出异常
133+
pool.setThreadInitCallback([](){
134+
throw std::runtime_error("Init error");
135+
});
136+
137+
pool.start();
138+
139+
// 任务应该仍然能够执行
140+
for (int i = 0; i < 10; ++i)
141+
{
142+
pool.exec([&taskCount](){
143+
taskCount++;
144+
});
145+
}
146+
147+
pool.waitForAllDone();
148+
pool.stop();
149+
150+
// 验证任务都被执行了
151+
EXPECT_EQ(taskCount.load(), 10);
152+
}
153+
154+
TEST_F(UtilThreadPollTest, testSetCallbackAfterStart)
155+
{
156+
TC_ThreadPool pool;
157+
pool.init(2);
158+
pool.start();
159+
160+
// 应该抛出异常
161+
EXPECT_THROW(
162+
pool.setThreadInitCallback([](){}),
163+
TC_ThreadPool_Exception
164+
);
165+
166+
EXPECT_THROW(
167+
pool.setThreadDestroyCallback([](){}),
168+
TC_ThreadPool_Exception
169+
);
170+
171+
pool.stop();
58172
}

util/include/util/tc_thread_pool.h

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,31 @@ namespace tars
2323
* 使用说明:
2424
* TC_ThreadPool tpool;
2525
* tpool.init(5); //初始化线程池线程数
26-
* //启动线程有两种方式
27-
* //第一种, 直接启动
26+
*
27+
* //设置线程生命周期回调(可选)
28+
* tpool.setThreadInitCallback([](){
29+
* //线程初始化代码,每个工作线程启动时执行一次
30+
* //可以初始化 thread_local 变量
31+
* });
32+
* tpool.setThreadDestroyCallback([](){
33+
* //线程清理代码,每个工作线程退出前执行一次
34+
* //可以清理 thread_local 资源
35+
* });
36+
*
37+
* //启动线程
2838
* tpool.start();
29-
* //第二种, 启动时指定初始化函数, 比如定义函数
30-
* void testFunction(int i)
31-
* {
32-
* cout << i << endl;
33-
* }
34-
* tpool.start(testFunction, 5); //start的第一函数是std::bind返回的函数(std::function), 后面跟参数
39+
*
3540
* //将任务丢到线程池中
3641
* tpool.exec(testFunction, 10); //参数和start相同
42+
*
3743
* //等待线程池结束, 有两种方式:
3844
* //第一种等待线程池中无任务
3945
* tpool.waitForAllDone(1000); //参数<0时, 表示无限等待(注意有人调用stop也会推出)
4046
* //第二种等待外部有人调用线程池的stop函数
4147
* tpool.waitForStop(1000);
4248
* //此时: 外部需要结束线程池是调用
4349
* tpool.stop();
50+
*
4451
* 注意:
4552
* TC_ThreadPool::exec执行任务返回的是个future, 因此可以通过future异步获取结果, 比如:
4653
* int testInt(int i)
@@ -91,6 +98,18 @@ class UTIL_DLL_API TC_ThreadPool
9198
};
9299
typedef shared_ptr<TaskFunc> TaskFuncPtr;
93100
public:
101+
/**
102+
* @brief 线程初始化回调函数类型
103+
* 在工作线程启动后、执行任务前调用(每个线程仅调用一次)
104+
*/
105+
typedef std::function<void()> ThreadInitCallback;
106+
107+
/**
108+
* @brief 线程销毁回调函数类型
109+
* 在工作线程退出前调用(每个线程仅调用一次)
110+
*/
111+
typedef std::function<void()> ThreadDestroyCallback;
112+
94113
/**
95114
* @brief 构造函数
96115
*
@@ -142,6 +161,30 @@ class UTIL_DLL_API TC_ThreadPool
142161
*/
143162
void start();
144163

164+
/**
165+
* @brief 设置线程初始化回调函数
166+
*
167+
* @param callback 初始化回调函数,在每个工作线程启动时调用
168+
*
169+
* 注意:
170+
* - 必须在 start() 之前调用
171+
* - 回调函数在工作线程中执行,可以安全地访问 TLS 变量
172+
* - 如果回调函数抛出异常,异常会被捕获并忽略,线程继续运行
173+
*/
174+
void setThreadInitCallback(const ThreadInitCallback& callback);
175+
176+
/**
177+
* @brief 设置线程销毁回调函数
178+
*
179+
* @param callback 销毁回调函数,在每个工作线程退出前调用
180+
*
181+
* 注意:
182+
* - 必须在 start() 之前调用
183+
* - 回调函数在工作线程中执行,可以安全地访问 TLS 变量
184+
* - 如果回调函数抛出异常,异常会被捕获并忽略
185+
*/
186+
void setThreadDestroyCallback(const ThreadDestroyCallback& callback);
187+
145188
/**
146189
* @brief 用线程池启用任务(F是function, Args是参数)
147190
*
@@ -230,6 +273,10 @@ class UTIL_DLL_API TC_ThreadPool
230273
bool _bTerminate;
231274

232275
std::atomic<int> _atomic{ 0 };
276+
277+
ThreadInitCallback _threadInitCallback;
278+
279+
ThreadDestroyCallback _threadDestroyCallback;
233280
};
234281

235282

@@ -260,6 +307,24 @@ class UTIL_DLL_API TC_ThreadPoolHash
260307
*/
261308
void start();
262309

310+
/**
311+
* @brief 设置所有线程池的初始化回调
312+
*
313+
* @param callback 初始化回调函数
314+
*
315+
* 注意:必须在 start() 之前调用
316+
*/
317+
void setThreadInitCallback(const TC_ThreadPool::ThreadInitCallback& callback);
318+
319+
/**
320+
* @brief 设置所有线程池的销毁回调
321+
*
322+
* @param callback 销毁回调函数
323+
*
324+
* 注意:必须在 start() 之前调用
325+
*/
326+
void setThreadDestroyCallback(const TC_ThreadPool::ThreadDestroyCallback& callback);
327+
263328
/**
264329
* @brief 用线程池启用任务(F是function, Args是参数)
265330
*
@@ -302,7 +367,9 @@ class UTIL_DLL_API TC_ThreadPoolHash
302367
protected:
303368
private:
304369
vector<TC_ThreadPool*> _pools;
305-
370+
371+
TC_ThreadPool::ThreadInitCallback _threadInitCallback;
372+
TC_ThreadPool::ThreadDestroyCallback _threadDestroyCallback;
306373
};
307374

308375
}

util/src/tc_thread_pool.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,32 @@ void TC_ThreadPool::start()
9090
}
9191
}
9292

93+
void TC_ThreadPool::setThreadInitCallback(const ThreadInitCallback& callback)
94+
{
95+
std::unique_lock<std::mutex> lock(_mutex);
96+
97+
if (!_threads.empty())
98+
{
99+
throw TC_ThreadPool_Exception(
100+
"[TC_ThreadPool::setThreadInitCallback] cannot set callback after thread pool started!");
101+
}
102+
103+
_threadInitCallback = callback;
104+
}
105+
106+
void TC_ThreadPool::setThreadDestroyCallback(const ThreadDestroyCallback& callback)
107+
{
108+
std::unique_lock<std::mutex> lock(_mutex);
109+
110+
if (!_threads.empty())
111+
{
112+
throw TC_ThreadPool_Exception(
113+
"[TC_ThreadPool::setThreadDestroyCallback] cannot set callback after thread pool started!");
114+
}
115+
116+
_threadDestroyCallback = callback;
117+
}
118+
93119
bool TC_ThreadPool::get(TaskFuncPtr& task)
94120
{
95121
std::unique_lock<std::mutex> lock(_mutex);
@@ -116,6 +142,19 @@ bool TC_ThreadPool::get(TaskFuncPtr& task)
116142

117143
void TC_ThreadPool::run()
118144
{
145+
// 线程初始化回调
146+
if (_threadInitCallback)
147+
{
148+
try
149+
{
150+
_threadInitCallback();
151+
}
152+
catch (...)
153+
{
154+
// 捕获异常,防止线程启动失败
155+
}
156+
}
157+
119158
//调用处理部分
120159
while (!isTerminate())
121160
{
@@ -149,6 +188,19 @@ void TC_ThreadPool::run()
149188
}
150189
}
151190
}
191+
192+
// 线程退出回调
193+
if (_threadDestroyCallback)
194+
{
195+
try
196+
{
197+
_threadDestroyCallback();
198+
}
199+
catch (...)
200+
{
201+
// 捕获异常,确保线程正常退出
202+
}
203+
}
152204
}
153205

154206
bool TC_ThreadPool::waitForAllDone(int millsecond)
@@ -187,10 +239,39 @@ void TC_ThreadPoolHash::init(size_t num)
187239
{
188240
TC_ThreadPool* p = new TC_ThreadPool();
189241
p->init(1);
242+
243+
// 应用回调
244+
if (_threadInitCallback)
245+
{
246+
p->setThreadInitCallback(_threadInitCallback);
247+
}
248+
if (_threadDestroyCallback)
249+
{
250+
p->setThreadDestroyCallback(_threadDestroyCallback);
251+
}
252+
190253
_pools.push_back(p);
191254
}
192255
}
193256

257+
void TC_ThreadPoolHash::setThreadInitCallback(const TC_ThreadPool::ThreadInitCallback& callback)
258+
{
259+
_threadInitCallback = callback;
260+
for (auto pool : _pools)
261+
{
262+
pool->setThreadInitCallback(callback);
263+
}
264+
}
265+
266+
void TC_ThreadPoolHash::setThreadDestroyCallback(const TC_ThreadPool::ThreadDestroyCallback& callback)
267+
{
268+
_threadDestroyCallback = callback;
269+
for (auto pool : _pools)
270+
{
271+
pool->setThreadDestroyCallback(callback);
272+
}
273+
}
274+
194275
TC_ThreadPool* TC_ThreadPoolHash::getThread(size_t index)
195276
{
196277
if (_pools.empty() || (index + 1) > _pools.size())

0 commit comments

Comments
 (0)