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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wallwind/article/details/49701397

之前有人问我设计一个分布式的递增的唯一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



猜你喜欢

转载自blog.csdn.net/wallwind/article/details/49701397