Skip to content

Commit 388512d

Browse files
committed
[新增Singleton模块]: 添加现代化线程安全的单例模式实现
-**新增**: 添加Singleton模块,包含模板化的单例基类,使用C++11特性确保线程安全 -**新增**: 实现SINGLETON宏,简化单例类的定义,自动处理拷贝和移动操作的禁用 -**新增**: 提供完整的单元测试,验证单例的唯一性、线程安全性、功能正确性等特性 -**更新**: 在项目README中新增Singleton模块说明,更新代码结构目录 -**更新**: 在根CMakeLists.txt中添加Singleton子目录,集成到项目构建系统中 -**修改**: 调整Thread模块单元测试,将空任务改为短暂睡眠以避免线程立即停止
1 parent 0a4c867 commit 388512d

File tree

6 files changed

+298
-7
lines changed

6 files changed

+298
-7
lines changed

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
## 项目概述
99

10-
这个项目收集了各种 C++ 编程中的实用示例,涵盖了系统编程、加密算法、多线程、崩溃处理等多个领域。每个示例都力求简洁明了,便于学习和在实际项目中使用。
10+
这个项目收集了各种 C++ 编程中的实用示例,涵盖了系统编程、加密算法、多线程、崩溃处理、设计模式等多个领域。每个示例都力求简洁明了,便于学习和在实际项目中使用。
1111

1212
## 代码结构
1313

@@ -71,7 +71,14 @@ OpenSSL 加密算法使用示例。
7171
- `openssl_hash.cc` - SHA256 哈希计算示例
7272
- `openssl_rsa.cc` - RSA 加解密示例
7373

74-
### 8. [Thread](src/Thread/)
74+
### 8. [Singleton](src/Singleton/)
75+
76+
现代化线程安全的单例模式实现,使用 C++11 特性确保跨平台兼容性。
77+
78+
- `singleton.hpp` - 模板化的单例基类,提供线程安全的实例访问
79+
- `singleton_unitest.cc` - 完整的单元测试,验证单例的唯一性、线程安全性等特性
80+
81+
### 9. [Thread](src/Thread/)
7582

7683
基于 std::jthread 实现的线程和线程池(注意:Apple Clang 不支持)。
7784

@@ -80,7 +87,7 @@ OpenSSL 加密算法使用示例。
8087
- `queue.hpp` - 线程安全队列
8188
- `*_unittest.cc` - 各组件单元测试
8289

83-
### 9. [utils](src/utils/)
90+
### 10. [utils](src/utils/)
8491

8592
通用工具类。
8693

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ add_subdirectory(Crashpad)
44
add_subdirectory(Memcpy)
55
add_subdirectory(MonitorDir)
66
add_subdirectory(MonitorDir_EFSW)
7+
add_subdirectory(Singleton)
78
add_subdirectory(OpenSSL)
89

910
if(CMAKE_HOST_WIN32)

src/Singleton/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
add_executable(singleton_unitest singleton_unitest.cc singleton.hpp)
2+
target_link_libraries(singleton_unitest PRIVATE GTest::gtest GTest::gtest_main
3+
GTest::gmock GTest::gmock_main)
4+
add_test(NAME singleton_unitest COMMAND singleton_unitest)

src/Singleton/singleton.hpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#pragma once
2+
3+
#include <utils/object.hpp>
4+
5+
template<typename T>
6+
class Singleton
7+
{
8+
DISABLE_COPY_MOVE(Singleton)
9+
public:
10+
static T &instance()
11+
{
12+
static T instance;
13+
return instance;
14+
}
15+
16+
static T *getInstance() { return &instance(); }
17+
18+
protected:
19+
Singleton() = default;
20+
virtual ~Singleton() = default;
21+
};
22+
23+
#define SINGLETON(Class) \
24+
private: \
25+
Class(const Class &) = delete; \
26+
Class &operator=(const Class &) = delete; \
27+
Class(Class &&) = delete; \
28+
Class &operator=(Class &&) = delete; \
29+
friend class Singleton<Class>; \
30+
\
31+
protected: \
32+
Class() = default; \
33+
\
34+
public: \
35+
static Class &instance() \
36+
{ \
37+
return Singleton<Class>::instance(); \
38+
}\

src/Singleton/singleton_unitest.cc

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
#include "singleton.hpp"
2+
3+
#include <gtest/gtest.h>
4+
5+
#include <atomic>
6+
#include <chrono>
7+
#include <future>
8+
#include <string>
9+
#include <thread>
10+
#include <vector>
11+
12+
// 测试用的单例类
13+
class TestSingleton : public Singleton<TestSingleton>
14+
{
15+
friend class Singleton<TestSingleton>;
16+
17+
private:
18+
TestSingleton()
19+
: value(0)
20+
{}
21+
22+
public:
23+
void setValue(int val) { value = val; }
24+
int getValue() const { return value; }
25+
void increment() { ++value; }
26+
27+
private:
28+
std::atomic<int> value;
29+
};
30+
31+
// 另一个测试用的单例类
32+
class AnotherSingleton
33+
{
34+
SINGLETON(AnotherSingleton)
35+
36+
public:
37+
std::string getName() const { return "AnotherSingleton"; }
38+
void setData(const std::string &data) { m_data = data; } // 重命名避免冲突
39+
std::string getData() const { return m_data; }
40+
41+
private:
42+
std::string m_data; // 重命名避免警告
43+
};
44+
45+
// 基础功能测试
46+
class SingletonTest : public ::testing::Test
47+
{
48+
protected:
49+
void SetUp() override
50+
{
51+
// 每个测试前重置单例状态(如果需要的话)
52+
}
53+
54+
void TearDown() override
55+
{
56+
// 清理工作
57+
}
58+
};
59+
60+
// 测试单例实例的唯一性
61+
TEST_F(SingletonTest, InstanceUniqueness)
62+
{
63+
TestSingleton &instance1 = TestSingleton::instance();
64+
TestSingleton &instance2 = TestSingleton::instance();
65+
TestSingleton *instance3 = TestSingleton::getInstance();
66+
67+
// 验证所有获取方式返回的是同一个实例
68+
EXPECT_EQ(&instance1, &instance2);
69+
EXPECT_EQ(&instance1, instance3);
70+
EXPECT_EQ(&instance2, instance3);
71+
}
72+
73+
// 测试单例的功能方法
74+
TEST_F(SingletonTest, Functionality)
75+
{
76+
TestSingleton &instance = TestSingleton::instance();
77+
78+
// 测试设置和获取值
79+
instance.setValue(42);
80+
EXPECT_EQ(instance.getValue(), 42);
81+
82+
// 测试修改值
83+
instance.increment();
84+
EXPECT_EQ(instance.getValue(), 43);
85+
}
86+
87+
// 测试多个单例类的独立性
88+
TEST_F(SingletonTest, MultipleSingletonIndependence)
89+
{
90+
TestSingleton &testInstance = TestSingleton::instance();
91+
AnotherSingleton &anotherInstance = AnotherSingleton::instance();
92+
93+
testInstance.setValue(100);
94+
anotherInstance.setData("test_data");
95+
96+
// 验证两个单例实例不冲突
97+
EXPECT_EQ(testInstance.getValue(), 100);
98+
EXPECT_EQ(anotherInstance.getData(), "test_data");
99+
EXPECT_NE(reinterpret_cast<void *>(&testInstance), reinterpret_cast<void *>(&anotherInstance));
100+
}
101+
102+
// 测试单例的不可拷贝和不可移动特性
103+
TEST_F(SingletonTest, NonCopyableNonMovable)
104+
{
105+
// 这些代码应该编译失败,我们通过SFINAE或编译时检查来验证
106+
// 在实际测试中,我们可以验证这些特性是否存在
107+
108+
EXPECT_TRUE(std::is_copy_constructible_v<TestSingleton> == false);
109+
EXPECT_TRUE(std::is_copy_assignable_v<TestSingleton> == false);
110+
EXPECT_TRUE(std::is_move_constructible_v<TestSingleton> == false);
111+
EXPECT_TRUE(std::is_move_assignable_v<TestSingleton> == false);
112+
}
113+
114+
// 辅助函数用于多线程测试
115+
void threadTask(int threadId, std::promise<TestSingleton *> &promise)
116+
{
117+
(void) threadId; // 标记未使用参数,消除警告
118+
TestSingleton &instance = TestSingleton::instance();
119+
instance.increment(); // 每个线程增加一次
120+
promise.set_value(&instance);
121+
}
122+
123+
// 多线程安全性测试
124+
TEST_F(SingletonTest, ThreadSafety)
125+
{
126+
constexpr int numThreads = 10;
127+
128+
// 创建一个新的单例类用于线程测试
129+
class ThreadTestSingleton : public Singleton<ThreadTestSingleton>
130+
{
131+
friend class Singleton<ThreadTestSingleton>;
132+
133+
private:
134+
ThreadTestSingleton()
135+
: counter(0)
136+
{}
137+
138+
public:
139+
void increment() { ++counter; }
140+
int getCounter() const { return counter; }
141+
142+
private:
143+
std::atomic<int> counter;
144+
};
145+
146+
// 启动多个线程同时访问单例
147+
std::vector<std::thread> testThreads;
148+
std::vector<std::future<ThreadTestSingleton *>> testFutures;
149+
std::vector<std::promise<ThreadTestSingleton *>> testPromises(numThreads);
150+
151+
for (auto &promise : testPromises) {
152+
testFutures.push_back(promise.get_future());
153+
}
154+
155+
for (int i = 0; i < numThreads; ++i) {
156+
testThreads.emplace_back([i, &testPromises]() {
157+
ThreadTestSingleton &instance = ThreadTestSingleton::instance();
158+
instance.increment();
159+
testPromises[i].set_value(&instance);
160+
});
161+
}
162+
163+
// 等待所有线程完成
164+
for (auto &thread : testThreads) {
165+
thread.join();
166+
}
167+
168+
// 验证所有线程获取的是同一个实例
169+
ThreadTestSingleton *firstInstance = testFutures[0].get();
170+
for (size_t i = 1; i < testFutures.size(); ++i) {
171+
EXPECT_EQ(firstInstance, testFutures[i].get());
172+
}
173+
174+
// 验证计数器值正确(每个线程增加了一次)
175+
EXPECT_EQ(firstInstance->getCounter(), numThreads);
176+
}
177+
178+
// 测试单例的继承特性
179+
class DerivedSingleton : public Singleton<DerivedSingleton>
180+
{
181+
friend class Singleton<DerivedSingleton>;
182+
183+
private:
184+
DerivedSingleton()
185+
: specialValue(999)
186+
{}
187+
188+
public:
189+
int getSpecialValue() const { return specialValue; }
190+
virtual std::string getType() { return "DerivedSingleton"; }
191+
192+
private:
193+
int specialValue;
194+
};
195+
196+
TEST_F(SingletonTest, Inheritance)
197+
{
198+
DerivedSingleton &instance = DerivedSingleton::instance();
199+
EXPECT_EQ(instance.getSpecialValue(), 999);
200+
EXPECT_EQ(instance.getType(), "DerivedSingleton");
201+
}
202+
203+
// 性能测试(可选)
204+
TEST_F(SingletonTest, Performance)
205+
{
206+
auto start = std::chrono::high_resolution_clock::now(); // 修正后的代码
207+
208+
constexpr int iterations = 100000;
209+
for (int i = 0; i < iterations; ++i) {
210+
TestSingleton &instance = TestSingleton::instance();
211+
(void) instance; // 避免未使用变量警告
212+
}
213+
214+
auto end = std::chrono::high_resolution_clock::now(); // 修正后的代码
215+
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
216+
217+
// 验证获取实例的时间在合理范围内
218+
// 这个阈值可能需要根据具体环境调整
219+
EXPECT_LT(duration.count(), 1000000); // 小于1秒
220+
}
221+
222+
// 测试单例宏的正确性
223+
TEST_F(SingletonTest, MacroUsage)
224+
{
225+
// 验证使用宏的单例类具有正确的特性
226+
EXPECT_FALSE(std::is_default_constructible_v<AnotherSingleton>);
227+
EXPECT_FALSE(std::is_copy_constructible_v<AnotherSingleton>);
228+
EXPECT_FALSE(std::is_copy_assignable_v<AnotherSingleton>);
229+
EXPECT_FALSE(std::is_move_constructible_v<AnotherSingleton>);
230+
EXPECT_FALSE(std::is_move_assignable_v<AnotherSingleton>);
231+
232+
// 验证实例方法存在且工作正常
233+
AnotherSingleton &instance = AnotherSingleton::instance();
234+
EXPECT_EQ(instance.getName(), "AnotherSingleton");
235+
}
236+
237+
// 主函数
238+
int main(int argc, char **argv)
239+
{
240+
::testing::InitGoogleTest(&argc, argv);
241+
return RUN_ALL_TESTS();
242+
}

src/Thread/thread_unittest.cc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,11 +372,10 @@ TEST_F(ThreadTest, RapidStartStop)
372372
std::vector<std::unique_ptr<Thread>> threads;
373373

374374
for (int i = 0; i < NUM_THREADS; ++i) {
375-
auto thread = std::make_unique<Thread>([](std::stop_token token) {
376-
// 空任务,立即返回
377-
});
375+
auto thread = std::make_unique<Thread>(
376+
[](std::stop_token token) { std::this_thread::sleep_for(10ms); });
378377

379-
EXPECT_FALSE(thread->start()); // 线程状态很快变为Stopped
378+
EXPECT_TRUE(thread->start());
380379
threads.push_back(std::move(thread));
381380
}
382381

0 commit comments

Comments
 (0)