snowflake.h
/** * snowflake.h * * nextId() * * nextIdFrom(unsigned char datacenterId, unsigned char workerId) * **/ #include <stdint.h> // 定义起始的日期时间戳 #define EPOCH 1584340752713ULL // 获取默认id uint64_t nextId(void); // 从指定的数据中心的指定的工作站获取id uint64_t nextIdFrom(unsigned char, unsigned char);
snowflake.c
/** * filename: snowflake.c * * date: 2020-2-20 20:20:02 * * description: 分布式全局唯一标识, * Twitter的Snowflake算法的c语言实现(单线程)。 * **/ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <sys/timeb.h> #include "snowflake.h" // 默认的数据中心标识 const unsigned char DEFAULT_DATACENTER_ID = 0; // 默认的工作站标识 const unsigned char DEFAULT_WORKER_ID = 0; uint64_t BASE_TIMESTAMP_MILLISEC = EPOCH; //EPOCH在snowflake.h中定义 uint64_t last_timestamp_millisec = 0; uint64_t current_timestamp_millisec = 0; unsigned short squenceNumber = 0; // _Bool invalidWorkerId(const unsigned char, const unsigned char); // 当前毫秒时间戳 void setCurrentTimeStampMillis(uint64_t *); uint64_t nextId(void) { return nextIdFrom(DEFAULT_DATACENTER_ID, DEFAULT_WORKER_ID); } uint64_t nextIdFrom(unsigned char datacenterId, unsigned char workerId) { invalidWorkerId(datacenterId, workerId); //datacenterId &= 0x1F; //workerId &= 0x1F; setCurrentTimeStampMillis(¤t_timestamp_millisec); if (squenceNumber >= 0xfff) { squenceNumber = 0; do { setCurrentTimeStampMillis(¤t_timestamp_millisec); } while (current_timestamp_millisec <= last_timestamp_millisec); last_timestamp_millisec = current_timestamp_millisec; } uint64_t timeStamp = current_timestamp_millisec - BASE_TIMESTAMP_MILLISEC; uint64_t id = (timeStamp << 22) | (datacenterId << 17) | (workerId << 12) | squenceNumber++ & 0xfff; return id; } _Bool invalidWorkerId(const unsigned char datacenterId, const unsigned char workerId) { if (datacenterId >= 32 || workerId >= 32){ fprintf(stderr, "[nextIdFrom() @ snowflake.c] " "ERROR! datacenterId and workerId both " "must be unsigned integer between 0 to 31, " "application exit!\n"); exit(-1); // other way: return 0 here; } return 1; } void setCurrentTimeStampMillis(uint64_t * millisec) { struct timeb stCurrentTimeStamp; ftime(&stCurrentTimeStamp); (*millisec) = (uint64_t)stCurrentTimeStamp.time * 1000 + (uint64_t)stCurrentTimeStamp.millitm; }
main.c
#include <stdio.h> #include "snowflake.h" int main(void) { for (int i = 0; i < 600; i++) { printf("id[%4d]=%20I64u\n", i + 1, nextId() ); } return 0; }