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

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



  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Java 中实现分布式自增 ID 可以使用 Snowflake 算法,该算法使用一个 64 位的二进制数字,其中前 41 位为时间戳,接着是 10 位的机器 ID 和 12 位的序列号。 以下是一个简单的 Java 实现: ```java public class SnowflakeIdGenerator { // 开始时间戳(2021-01-01) private final static long START_TIMESTAMP = 1609430400000L; // 机器 ID 所占位数 private final static long MACHINE_BITS = 10L; // 序列号所占位数 private final static long SEQUENCE_BITS = 12L; // 最大机器 ID private final static long MAX_MACHINE_ID = ~(-1L << MACHINE_BITS); // 最大序列号 private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS); // 机器 ID 左移位数 private final static long MACHINE_SHIFT = SEQUENCE_BITS; // 时间戳左移位数 private final static long TIMESTAMP_SHIFT = MACHINE_BITS + SEQUENCE_BITS; // 当前机器 ID private long machineId; // 当前序列号 private long sequence = 0L; // 上次生成 ID 的时间戳 private long lastTimestamp = -1L; public SnowflakeIdGenerator(long machineId) { if (machineId > MAX_MACHINE_ID || machineId < 0) { throw new IllegalArgumentException(String.format("Machine ID can't be greater than %d or less than 0", MAX_MACHINE_ID)); } this.machineId = machineId; } public synchronized long nextId() { long timestamp = System.currentTimeMillis(); if (timestamp < lastTimestamp) { throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); } if (timestamp == lastTimestamp) { sequence = (sequence + 1) & MAX_SEQUENCE; if (sequence == 0) { timestamp = nextTimestamp(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; return ((timestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT) | (machineId << MACHINE_SHIFT) | sequence; } private long nextTimestamp(long lastTimestamp) { long timestamp = System.currentTimeMillis(); while (timestamp <= lastTimestamp) { timestamp = System.currentTimeMillis(); } return timestamp; } } ``` 使用示例: ```java SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1); long id = idGenerator.nextId(); ``` 该实现中,机器 ID 和序列号都是自增的,时间戳取当前时间,如果当前时间小于上一次生成 ID 的时间戳,则抛出异常。如果当前时间等于上一次生成 ID 的时间戳,则序列号自增,如果序列号超过最大值,则等待下一个时间戳。如果当前时间大于上一次生成 ID 的时间戳,则序列号重置为 0。最后,将时间戳、机器 ID 和序列号拼接成一个 64 位的二进制数字作为 ID 返回。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值