实现c++版本
This commit is contained in:
49
CPP/README.md
Normal file
49
CPP/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# ❄ idgenerator-CPP
|
||||
|
||||
## 编译说明
|
||||
|
||||
跨平台,只需要该系统有C++11或以上编译器就可以编译使用。
|
||||
|
||||
## 使用方式
|
||||
只需要包含 IdGenerator.h 头文件即可
|
||||
#include "idgen/IdGenerator.h"
|
||||
|
||||
## 调用示例(CPP)
|
||||
|
||||
第1步,**全局** 初始化(应用程序启动时执行一次,实际上代码保证了初始化只能运行一次):
|
||||
```c
|
||||
// 初始化方式1:
|
||||
idgen::IdGeneratorOptions options;
|
||||
options.Method = method;
|
||||
options.WorkerId = 1; // Your_Unique_Worker_Id
|
||||
options.SeqBitLength = 10; // 默认值6,限制每毫秒生成的ID个数。若生成速度超过5万个/秒,建议加大 SeqBitLength 到 10。
|
||||
// options.WorkerIdBitLength = 10; // 默认值6,限定 WorkerId 最大值为2^6-1,即默认最多支持64个节点。
|
||||
// options.BaseTime = Your_Base_Time; // 如果要兼容老系统的雪花算法,此处应设置为老系统的BaseTime。
|
||||
idgen::IdGenerator::CreateInstance(options);
|
||||
|
||||
// 初始化方式2:
|
||||
// 或者如果使用默认的options参数, 只需要
|
||||
//idgen::IdGenerator::CreateInstance(Your_Unique_Worker_Id);
|
||||
|
||||
// 以上过程只需全局一次,且应在生成ID之前完成。
|
||||
```
|
||||
|
||||
第2步,生成ID:
|
||||
```c
|
||||
// 初始化后,在任何需要生成ID的地方,调用以下方法:
|
||||
long newId = idgen::IdGenerator::NextId();
|
||||
```
|
||||
|
||||
## 编译示例(CPP)
|
||||
```shell
|
||||
如果c++编译器默认是c++11以前的,但支持c++11, 编译的时候需要加上 -std=c++11, 类似:
|
||||
g++ -std=c++11 -pthread -g -W -O2 main.cpp -o testcpp
|
||||
|
||||
如果c++编译器默认就是c++11或以上的,只需类似:
|
||||
g++ -pthread -g -W -O2 main.cpp -o testcpp
|
||||
|
||||
编译完毕后,可以运行,例如:
|
||||
./testcpp > testcpp.log
|
||||
|
||||
|
||||
```
|
||||
428
CPP/source/idgen/IdGenerator.h
Normal file
428
CPP/source/idgen/IdGenerator.h
Normal file
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* 版权属于:yitter(yitter@126.com)
|
||||
* 翻译为C++代码:fuzhufang(fuzhufang@126.com)
|
||||
* 开源地址:https://github.com/yitter/idgenerator
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <assert.h>
|
||||
#include <cstdint>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <stdexcept>
|
||||
// #include <sys/time.h>
|
||||
|
||||
namespace idgen
|
||||
{
|
||||
typedef struct IdGenOptions
|
||||
{
|
||||
/// 雪花计算方法,(1-漂移算法|2-传统算法),默认1
|
||||
uint8_t Method{1};
|
||||
|
||||
/// 基础时间(ms单位),不能超过当前系统时间
|
||||
uint64_t BaseTime{1582136402000};
|
||||
|
||||
/// 机器码,必须由外部设定,最大值 2^WorkerIdBitLength-1
|
||||
uint32_t WorkerId{0};
|
||||
|
||||
/// 机器码位长,默认值6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过22)
|
||||
uint8_t WorkerIdBitLength{6};
|
||||
|
||||
/// 序列数位长,默认值6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过22)
|
||||
uint8_t SeqBitLength{6};
|
||||
|
||||
/// 最大序列数(含),设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值0,表示最大序列数取最大值(2^SeqBitLength-1])
|
||||
uint32_t MaxSeqNumber{0};
|
||||
|
||||
/// 最小序列数(含),默认值5,取值范围 [5, MaxSeqNumber],每毫秒的前5个序列数对应编号0-4是保留位,其中1-4是时间回拨相应预留位,0是手工新值预留位
|
||||
uint32_t MinSeqNumber{5};
|
||||
|
||||
/// 最大漂移次数(含),默认2000,推荐范围 500-20000(与计算能力有关)
|
||||
uint32_t TopOverCostCount{2000};
|
||||
|
||||
} IdGeneratorOptions;
|
||||
|
||||
typedef struct SnowFlakeWorker
|
||||
{
|
||||
/// 雪花计算方法,(1-漂移算法|2-传统算法),默认1
|
||||
uint8_t Method{0};
|
||||
|
||||
/// 基础时间
|
||||
uint64_t BaseTime{0};
|
||||
|
||||
/// 机器码
|
||||
uint32_t WorkerId{0};
|
||||
|
||||
/// 机器码位长
|
||||
uint8_t WorkerIdBitLength{0};
|
||||
|
||||
/// 自增序列数位长
|
||||
uint8_t SeqBitLength{0};
|
||||
|
||||
/// 最大序列数(含)
|
||||
uint32_t MaxSeqNumber{0};
|
||||
|
||||
/// 最小序列数(含)
|
||||
uint32_t MinSeqNumber{0};
|
||||
|
||||
/// 最大漂移次数(含)
|
||||
uint32_t TopOverCostCount{0};
|
||||
|
||||
uint8_t _TimestampShift{0};
|
||||
uint32_t _CurrentSeqNumber{0};
|
||||
int64_t _LastTimeTick{0};
|
||||
int64_t _TurnBackTimeTick{0};
|
||||
uint8_t _TurnBackIndex{0};
|
||||
bool _IsOverCost{false};
|
||||
uint32_t _OverCostCountInOneTerm{0};
|
||||
uint32_t _GenCountInOneTerm{0};
|
||||
uint32_t _TermIndex{0};
|
||||
|
||||
} SnowFlakeWorker;
|
||||
|
||||
inline static int64_t GetCurrentTime()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
inline static int64_t GetCurrentMicroTime()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
return duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
class SnowWorker
|
||||
{
|
||||
public:
|
||||
int64_t GetCurrentTimeTick()
|
||||
{
|
||||
return GetCurrentTime() - (int64_t)_SnowFlakeWorker.BaseTime;
|
||||
}
|
||||
|
||||
int64_t GetNextTimeTick()
|
||||
{
|
||||
int64_t tempTimeTicker = GetCurrentTimeTick();
|
||||
while (tempTimeTicker <= _SnowFlakeWorker._LastTimeTick)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // 暂停1ms
|
||||
tempTimeTicker = GetCurrentTimeTick();
|
||||
}
|
||||
return tempTimeTicker;
|
||||
}
|
||||
|
||||
void EndOverCostAction(int64_t useTimeTick)
|
||||
{
|
||||
// if (_SnowFlakeWorker._TermIndex > 10000) {
|
||||
// _SnowFlakeWorker._TermIndex = 0;
|
||||
// }
|
||||
}
|
||||
|
||||
int64_t NextOverCostId()
|
||||
{
|
||||
int64_t currentTimeTick = GetCurrentTimeTick();
|
||||
if (currentTimeTick > _SnowFlakeWorker._LastTimeTick)
|
||||
{
|
||||
EndOverCostAction(currentTimeTick);
|
||||
_SnowFlakeWorker._LastTimeTick = currentTimeTick;
|
||||
_SnowFlakeWorker._CurrentSeqNumber = _SnowFlakeWorker.MinSeqNumber;
|
||||
_SnowFlakeWorker._IsOverCost = false;
|
||||
_SnowFlakeWorker._OverCostCountInOneTerm = 0;
|
||||
_SnowFlakeWorker._GenCountInOneTerm = 0;
|
||||
return CalcId();
|
||||
}
|
||||
if (_SnowFlakeWorker._OverCostCountInOneTerm > _SnowFlakeWorker.TopOverCostCount)
|
||||
{
|
||||
EndOverCostAction(currentTimeTick);
|
||||
_SnowFlakeWorker._LastTimeTick = GetNextTimeTick();
|
||||
_SnowFlakeWorker._CurrentSeqNumber = _SnowFlakeWorker.MinSeqNumber;
|
||||
_SnowFlakeWorker._IsOverCost = false;
|
||||
_SnowFlakeWorker._OverCostCountInOneTerm = 0;
|
||||
_SnowFlakeWorker._GenCountInOneTerm = 0;
|
||||
return CalcId();
|
||||
}
|
||||
if (_SnowFlakeWorker._CurrentSeqNumber > _SnowFlakeWorker.MaxSeqNumber)
|
||||
{
|
||||
_SnowFlakeWorker._LastTimeTick++;
|
||||
_SnowFlakeWorker._CurrentSeqNumber = _SnowFlakeWorker.MinSeqNumber;
|
||||
_SnowFlakeWorker._IsOverCost = true;
|
||||
_SnowFlakeWorker._OverCostCountInOneTerm++;
|
||||
_SnowFlakeWorker._GenCountInOneTerm++;
|
||||
return CalcId();
|
||||
}
|
||||
|
||||
_SnowFlakeWorker._GenCountInOneTerm++;
|
||||
return CalcId();
|
||||
}
|
||||
|
||||
int64_t NextNormalId()
|
||||
{
|
||||
int64_t currentTimeTick = GetCurrentTimeTick();
|
||||
if (currentTimeTick < _SnowFlakeWorker._LastTimeTick)
|
||||
{
|
||||
if (_SnowFlakeWorker._TurnBackTimeTick < 1)
|
||||
{
|
||||
_SnowFlakeWorker._TurnBackTimeTick = _SnowFlakeWorker._LastTimeTick - 1;
|
||||
_SnowFlakeWorker._TurnBackIndex++;
|
||||
// 每毫秒序列数的前 5 位是预留位,0 用于手工新值,1-4 是时间回拨次序
|
||||
// 支持 4 次回拨次序(避免回拨重叠导致 ID 重复),可无限次回拨(次序循环使用)。
|
||||
if (_SnowFlakeWorker._TurnBackIndex > 4)
|
||||
{
|
||||
_SnowFlakeWorker._TurnBackIndex = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(1));; // 暂停1ms
|
||||
return CalcTurnBackId();
|
||||
}
|
||||
|
||||
if (_SnowFlakeWorker._TurnBackTimeTick > 0)
|
||||
{
|
||||
_SnowFlakeWorker._TurnBackTimeTick = 0;
|
||||
}
|
||||
|
||||
if (currentTimeTick > _SnowFlakeWorker._LastTimeTick)
|
||||
{
|
||||
_SnowFlakeWorker._LastTimeTick = currentTimeTick;
|
||||
_SnowFlakeWorker._CurrentSeqNumber = _SnowFlakeWorker.MinSeqNumber;
|
||||
return CalcId();
|
||||
}
|
||||
|
||||
if (_SnowFlakeWorker._CurrentSeqNumber > _SnowFlakeWorker.MaxSeqNumber)
|
||||
{
|
||||
_SnowFlakeWorker._TermIndex++;
|
||||
_SnowFlakeWorker._LastTimeTick++;
|
||||
_SnowFlakeWorker._CurrentSeqNumber = _SnowFlakeWorker.MinSeqNumber;
|
||||
_SnowFlakeWorker._IsOverCost = true;
|
||||
_SnowFlakeWorker._OverCostCountInOneTerm = 1;
|
||||
_SnowFlakeWorker._GenCountInOneTerm = 1;
|
||||
return CalcId();
|
||||
}
|
||||
|
||||
return CalcId();
|
||||
}
|
||||
|
||||
int64_t CalcId()
|
||||
{
|
||||
uint64_t result = (_SnowFlakeWorker._LastTimeTick << _SnowFlakeWorker._TimestampShift) | (_SnowFlakeWorker.WorkerId << _SnowFlakeWorker.SeqBitLength) |
|
||||
(_SnowFlakeWorker._CurrentSeqNumber);
|
||||
_SnowFlakeWorker._CurrentSeqNumber++;
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t CalcTurnBackId()
|
||||
{
|
||||
uint64_t result = (_SnowFlakeWorker._LastTimeTick << _SnowFlakeWorker._TimestampShift) | (_SnowFlakeWorker.WorkerId << _SnowFlakeWorker.SeqBitLength) |
|
||||
(_SnowFlakeWorker._TurnBackIndex);
|
||||
_SnowFlakeWorker._TurnBackTimeTick--;
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t WorkerM1NextId()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_ThreadMutex);
|
||||
int64_t id = _SnowFlakeWorker._IsOverCost ? NextOverCostId() : NextNormalId();
|
||||
return id;
|
||||
}
|
||||
|
||||
int64_t WorkerM2NextId()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_ThreadMutex);
|
||||
|
||||
int64_t currentTimeTick = GetCurrentTimeTick();
|
||||
if (_SnowFlakeWorker._LastTimeTick == currentTimeTick)
|
||||
{
|
||||
_SnowFlakeWorker._CurrentSeqNumber = (++_SnowFlakeWorker._CurrentSeqNumber) & _SnowFlakeWorker.MaxSeqNumber;
|
||||
if (_SnowFlakeWorker._CurrentSeqNumber == 0)
|
||||
{
|
||||
currentTimeTick = GetNextTimeTick();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_SnowFlakeWorker._CurrentSeqNumber = _SnowFlakeWorker.MinSeqNumber;
|
||||
}
|
||||
|
||||
_SnowFlakeWorker._LastTimeTick = currentTimeTick;
|
||||
int64_t id = (int64_t)((currentTimeTick << _SnowFlakeWorker._TimestampShift) |
|
||||
(_SnowFlakeWorker.WorkerId << _SnowFlakeWorker.SeqBitLength) |
|
||||
_SnowFlakeWorker._CurrentSeqNumber);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void SetOptions(IdGeneratorOptions options)
|
||||
{
|
||||
// 1.BaseTime
|
||||
if (options.BaseTime == 0)
|
||||
{
|
||||
_SnowFlakeWorker.BaseTime = 1582136402000;
|
||||
}
|
||||
else if (options.BaseTime < 631123200000 || (int64_t)options.BaseTime > GetCurrentTime())
|
||||
{
|
||||
throw std::invalid_argument("BaseTime error.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_SnowFlakeWorker.BaseTime = options.BaseTime;
|
||||
}
|
||||
|
||||
// 2.WorkerIdBitLength
|
||||
if (options.WorkerIdBitLength <= 0)
|
||||
{
|
||||
throw std::invalid_argument("WorkerIdBitLength error.(range:[1, 21])");
|
||||
}
|
||||
if (options.SeqBitLength + options.WorkerIdBitLength > 22)
|
||||
{
|
||||
throw std::invalid_argument("error:WorkerIdBitLength + SeqBitLength <= 22");
|
||||
}
|
||||
else
|
||||
{
|
||||
// _SnowFlakeWorker.WorkerIdBitLength = options.WorkerIdBitLength;
|
||||
_SnowFlakeWorker.WorkerIdBitLength = options.WorkerIdBitLength <= 0 ? 6 : options.WorkerIdBitLength;
|
||||
}
|
||||
|
||||
// 3.WorkerId
|
||||
uint32_t maxWorkerIdNumber = (1 << options.WorkerIdBitLength) - 1;
|
||||
if (maxWorkerIdNumber == 0)
|
||||
{
|
||||
maxWorkerIdNumber = 63;
|
||||
}
|
||||
if (options.WorkerId > maxWorkerIdNumber)
|
||||
{
|
||||
throw std::invalid_argument("WorkerId error. (range:[0, {2^options.WorkerIdBitLength-1]}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_SnowFlakeWorker.WorkerId = options.WorkerId;
|
||||
}
|
||||
|
||||
// 4.SeqBitLength
|
||||
if (options.SeqBitLength < 2 || options.SeqBitLength > 21)
|
||||
{
|
||||
throw std::invalid_argument("SeqBitLength error. (range:[2, 21])");
|
||||
}
|
||||
else
|
||||
{
|
||||
_SnowFlakeWorker.SeqBitLength = options.SeqBitLength <= 0 ? 6 : options.SeqBitLength;
|
||||
}
|
||||
|
||||
// 5.MaxSeqNumber
|
||||
uint32_t maxSeqNumber = (1 << options.SeqBitLength) - 1;
|
||||
if (maxSeqNumber == 0)
|
||||
{
|
||||
maxSeqNumber = 63;
|
||||
}
|
||||
if (options.MaxSeqNumber > maxSeqNumber)
|
||||
{
|
||||
throw std::invalid_argument("MaxSeqNumber error. (range:[1, {2^options.SeqBitLength-1}]");
|
||||
}
|
||||
else
|
||||
{
|
||||
_SnowFlakeWorker.MaxSeqNumber = options.MaxSeqNumber <= 0 ? maxSeqNumber : options.MaxSeqNumber;
|
||||
}
|
||||
|
||||
// 6.MinSeqNumber
|
||||
if (options.MinSeqNumber < 5 || options.MinSeqNumber > maxSeqNumber)
|
||||
{
|
||||
throw std::invalid_argument("MinSeqNumber error. (range:[5, {options.MinSeqNumber}]");
|
||||
}
|
||||
else
|
||||
{
|
||||
_SnowFlakeWorker.MinSeqNumber = options.MinSeqNumber <= 0 ? 5 : options.MinSeqNumber;
|
||||
}
|
||||
|
||||
// 7.TopOverCostCount
|
||||
if (options.TopOverCostCount > 10000)
|
||||
{
|
||||
throw std::invalid_argument("TopOverCostCount error. (range:[0, 10000]");
|
||||
}
|
||||
else
|
||||
{
|
||||
//_SnowFlakeWorker.TopOverCostCount = options.TopOverCostCount <= 0 ? 2000 : options.TopOverCostCount;
|
||||
_SnowFlakeWorker.TopOverCostCount = options.TopOverCostCount;
|
||||
}
|
||||
|
||||
// 8.Others
|
||||
_SnowFlakeWorker._TimestampShift = _SnowFlakeWorker.WorkerIdBitLength + _SnowFlakeWorker.SeqBitLength;
|
||||
_SnowFlakeWorker._CurrentSeqNumber = _SnowFlakeWorker.MinSeqNumber;
|
||||
|
||||
_SnowFlakeWorker.Method = options.Method;
|
||||
if (options.Method == 2)
|
||||
{
|
||||
this->_NextId = &SnowWorker::WorkerM2NextId;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->_NextId = &SnowWorker::WorkerM1NextId;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
; // 暂停500ms
|
||||
}
|
||||
}
|
||||
|
||||
inline int64_t NextId()
|
||||
{
|
||||
return (this->*_NextId)();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::mutex _ThreadMutex;
|
||||
SnowFlakeWorker _SnowFlakeWorker;
|
||||
int64_t (SnowWorker::*_NextId)();
|
||||
};
|
||||
|
||||
class IdGenerator
|
||||
{
|
||||
public:
|
||||
// 禁止拷贝构造函数和赋值操作符
|
||||
IdGenerator(const IdGenerator &) = delete;
|
||||
IdGenerator &operator=(const IdGenerator &) = delete;
|
||||
|
||||
static void CreateInstance(uint32_t WorkerId)
|
||||
{
|
||||
IdGeneratorOptions options;
|
||||
options.WorkerId = WorkerId;
|
||||
CreateInstance(options);
|
||||
}
|
||||
|
||||
static void CreateInstance(IdGeneratorOptions options)
|
||||
{
|
||||
static std::once_flag initInstanceFlag;
|
||||
// 使用std::once_flag和std::call_once保证只初始化一次
|
||||
std::call_once(initInstanceFlag, [options]()
|
||||
{ createInstance(options); });
|
||||
}
|
||||
|
||||
static int64_t NextId()
|
||||
{
|
||||
assert(instance && "Please call CreateInstance first to create an instance");
|
||||
return instance->_sworker.NextId();
|
||||
}
|
||||
|
||||
private:
|
||||
IdGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
// 使用std::once_flag和std::call_once保证只初始化一次
|
||||
static void createInstance(IdGeneratorOptions options)
|
||||
{
|
||||
static IdGenerator obj;
|
||||
// 理论上保证了这个函数只会被调用一次,就算是多线程并发调用也不例外
|
||||
assert(nullptr == instance && "Theoretically, it is guaranteed that this function will only be called once, even if it is called concurrently by multiple threads.");
|
||||
instance = &obj;
|
||||
instance->_sworker.SetOptions(options);
|
||||
// printf("调用 %s \n", __FUNCTION__); // 在多个线程调用 CreateInstance 时候,看是否出现打印多次
|
||||
}
|
||||
|
||||
private:
|
||||
SnowWorker _sworker;
|
||||
|
||||
private:
|
||||
static IdGenerator *instance;
|
||||
};
|
||||
|
||||
IdGenerator *IdGenerator::instance = nullptr;
|
||||
|
||||
} // namespace idgen
|
||||
83
CPP/source/main.cpp
Normal file
83
CPP/source/main.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#include <inttypes.h>
|
||||
#include <vector>
|
||||
#include "idgen/IdGenerator.h"
|
||||
|
||||
const int GenIdCount = 500000;
|
||||
const bool multiThread = true;
|
||||
const int threadCount = 50;
|
||||
const int method = 1;
|
||||
|
||||
void RunMultiThread()
|
||||
{
|
||||
int64_t start = idgen::GetCurrentMicroTime();
|
||||
for (int i = 0; i < GenIdCount / threadCount; i++)
|
||||
{
|
||||
int64_t id = idgen::IdGenerator::NextId();
|
||||
printf("ID: %" PRId64 "\n", id);
|
||||
}
|
||||
|
||||
int64_t end = idgen::GetCurrentMicroTime();
|
||||
printf("%s,total:%" PRId64 " μs\n", method == 1 ? "1" : "2", (end - start));
|
||||
}
|
||||
|
||||
void RunSingle()
|
||||
{
|
||||
int64_t start = idgen::GetCurrentMicroTime();
|
||||
for (int i = 0; i < GenIdCount; i++)
|
||||
{
|
||||
int64_t id = idgen::IdGenerator::NextId();
|
||||
printf("ID: %" PRId64 "\n", id);
|
||||
}
|
||||
|
||||
int64_t end = idgen::GetCurrentMicroTime();
|
||||
|
||||
printf("%s, total: %" PRId64 " us\n", method == 1 ? "1" : "2", (end - start));
|
||||
}
|
||||
|
||||
void create_instance_fun()
|
||||
{
|
||||
idgen::IdGeneratorOptions options;
|
||||
options.Method = method;
|
||||
options.WorkerId = 1;
|
||||
options.SeqBitLength = 10;
|
||||
idgen::IdGenerator::CreateInstance(options);
|
||||
}
|
||||
|
||||
void test_multithread_run_create_instance()
|
||||
{
|
||||
std::vector<std::thread> threads;
|
||||
for (int i = 0; i < threadCount; i++)
|
||||
{
|
||||
threads.emplace_back(create_instance_fun);
|
||||
}
|
||||
for (auto &t : threads)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
if (multiThread) {
|
||||
test_multithread_run_create_instance(); // 测试多线程调用同时初始化,也确保只会安全初始化一次,确保单例唯一性
|
||||
} else {
|
||||
create_instance_fun(); // 单线程调用初始化
|
||||
}
|
||||
|
||||
if (multiThread)
|
||||
{
|
||||
std::vector<std::thread> threads;
|
||||
for (int i = 0; i < threadCount; i++)
|
||||
{
|
||||
threads.emplace_back(RunMultiThread);
|
||||
}
|
||||
for (auto &t : threads)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RunSingle();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user