您的位置:首页 > 编程语言 > C语言/C++

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

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

参考
https://github.com/twitter/snowflake
于是,我自己用c语言随便实现了一下,还没有达到工业级别,需要细化,但是基本能用了,上代码。

/*
snowflake

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

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <sched.h>
#include <linux/unistd.h>
#include <sys/syscall.h>
#include <errno.h>
#include<linux/types.h>
#include<time.h>
#include <stdint.h>
#include <sys/time.h>

struct globle
{
int global_int:12;
uint64_t last_stamp;
int workid;
int seqid;
};

void set_workid(int workid);
pid_t gettid( void );
uint64_t get_curr_ms();
uint64_t wait_next_ms(uint64_t lastStamp);
int atomic_incr(int id);
uint64_t get_unique_id();
#include "snowflake.h"

struct globle g_info;
#define   sequenceMask  (-1L ^ (-1L << 12L))
void set_workid(int workid)
{
g_info.workid = workid;
}
pid_t gettid( void )
{
return syscall( __NR_gettid );
}
uint64_t get_curr_ms()
{
struct timeval time_now;
gettimeofday(&time_now,NULL);
uint64_t ms_time =time_now.tv_sec*1000+time_now.tv_usec/1000;
return ms_time;
}

uint64_t wait_next_ms(uint64_t lastStamp)
{
uint64_t cur = 0;
do {
cur = get_curr_ms();
} while (cur <= lastStamp);
return cur;
}
int atomic_incr(int id)
{
__sync_add_and_fetch( &id, 1 );
return id;
}
uint64_t get_unique_id()
{
uint64_t  uniqueId=0;
uint64_t nowtime = get_curr_ms();
uniqueId = nowtime<<22;
uniqueId |=(g_info.workid&0x3ff)<<12;

if (nowtime <g_info.last_stamp)
{
perror("error");
exit(-1);
}
if (nowtime == g_info.last_stamp)
{
g_info.seqid = atomic_incr(g_info.seqid)& sequenceMask;
if (g_info.seqid ==0)
{
nowtime = wait_next_ms(g_info.last_stamp);
}
}
else
{
g_info.seqid  = 0;
}
g_info.last_stamp = nowtime;
uniqueId |=g_info.seqid;
return uniqueId;
}
int main()
{
set_workid(100);
int size;
for (;;)
{
uint64_t unquie = get_unique_id();
printf("pthread_id:%u, id [%llu]\n",gettid(),unquie);
}

return;
}


支持原子自增操作。

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

更多文章欢迎访问:http://blog.csdn.net/wallwind
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: