跳到主要内容

C语言实现分布式自增有序的唯一ID生成算法-snowflake算法

之前有人问我设计一个分布式的递增的唯一id生成。想了半天不知道,偶然一个同事说起snowflake算法,我百度了一下,很简单高效。

参考

https://github.com/twitter/snowflake

于是,我自己用c语言随便实现了一下,还没有达到工业级别,需要细化,但是基本能用了,上代码。

1.  /\* 
2.     snowflake 

4.     ID 生成策略 
5.     毫秒级时间41位+机器ID 10位+毫秒内序列12位。 
6.     0 41 51 64 +-----------+------+------+ |time |pc |inc | +-----------+------+------+ 
7.     前41bits是以微秒为单位的timestamp。 
8.     接着10bits是事先配置好的机器ID。 
9.     最后12bits是累加计数器。 
10.     macheine id(10bits)标明最多只能有1024台机器同时产生ID,sequence number(12bits)也标明1台机器1ms中最多产生4096个ID, \* 
11.       注意点,因为使用到位移运算,所以需要64位操作系统,不然生成的ID会有可能不正确 
12. \*/  

14. #include <stdio.h>  
15. #include <pthread.h>  
16. #include <unistd.h>  
17. #include <stdlib.h>  
18. #include <sched.h>  
19. #include <linux/unistd.h>  
20. #include <sys/syscall.h>  
21. #include <errno.h>  
22. #include<linux/types.h>  
23. #include<time.h>  
24. #include <stdint.h>  
25. #include <sys/time.h>  

27. struct  globle  
28. {  
29.     int global\_int:12;  
30.     uint64\_t last\_stamp;  
31.     int workid;  
32.     int seqid;  
33. };  

35. void set\_workid(int workid);  
36. pid\_t gettid( void );  
37. uint64\_t get\_curr\_ms();  
38. uint64\_t wait\_next\_ms(uint64\_t lastStamp);  
39. int atomic\_incr(int id);  
40. uint64\_t get\_unique\_id();  



1. #include "snowflake.h"  

3. struct globle g\_info;  
4. #define   sequenceMask  (-1L ^ (-1L << 12L))  
5. void set\_workid(int workid)  
6. {  
7.  g\_info.workid = workid;  
8. }  
9. pid\_t gettid( void )  
10. {  
11.     return syscall( \_\_NR\_gettid );  
12. }  
13. uint64\_t get\_curr\_ms()  
14. {  
15.     struct timeval time\_now;  
16.     gettimeofday(&time\_now,NULL);  
17.     uint64\_t ms\_time =time\_now.tv\_sec\*1000+time\_now.tv\_usec/1000;  
18.     return ms\_time;  
19. }  

21. uint64\_t wait\_next\_ms(uint64\_t lastStamp)  
22. {  
23.     uint64\_t cur = 0;  
24.     do {  
25.         cur = get\_curr\_ms();  
26.     } while (cur <= lastStamp);  
27.     return cur;  
28. }  
29. int atomic\_incr(int id)  
30. {  
31.     \_\_sync\_add\_and\_fetch( &id, 1 );  
32.     return id;  
33. }  
34. uint64\_t get\_unique\_id()  
35. {  
36.     uint64\_t  uniqueId=0;  
37.     uint64\_t nowtime = get\_curr\_ms();  
38.     uniqueId = nowtime<<22;  
39.     uniqueId |=(g\_info.workid&0x3ff)<<12;  

41.     if (nowtime <g\_info.last\_stamp)  
42.     {  
43.         perror("error");  
44.         exit(-1);  
45.     }  
46.     if (nowtime == g\_info.last\_stamp)  
47.     {  
48.         g\_info.seqid = atomic\_incr(g\_info.seqid)& sequenceMask;  
49.         if (g\_info.seqid ==0)  
50.         {  
51.             nowtime = wait\_next\_ms(g\_info.last\_stamp);  
52.         }  
53.     }  
54.     else  
55.     {  
56.         g\_info.seqid  = 0;  
57.     }  
58.     g\_info.last\_stamp = nowtime;  
59.     uniqueId |=g\_info.seqid;  
60.     return uniqueId;  
61. }  
62. int main()  
63. {  
64.     set\_workid(100);  
65.     int size;  
66.     for (;;)  
67.     {  
68.         uint64\_t unquie = get\_unique\_id();  
69.         printf("pthread\_id:%u, id \[%llu\]\\n",gettid(),unquie);  
70.     }  

72.     return;   
73. } 
 ```

支持原子自增操作。

多线程情况下,可以将workid进行移位加上线程ID。