C gettimeofday时钟\u生成唯一数字的gettime解决方案

C gettimeofday时钟\u生成唯一数字的gettime解决方案,c,linux,unique,gettimeofday,C,Linux,Unique,Gettimeofday,我的进程运行多个实例(进程)和多个线程,它们都写入同一个数据库。一旦发出请求,就会为要添加到专有数据库的记录生成唯一的req id。以下是我们的限制:长度不能超过9个字符,需要将HHMMS作为前6个字符。我们决定在最后3位使用ms来完成这9个字符,我们正在使用gettimeofday()完成所有这些操作。然而,随着通信量的增加,当在ms周期内放置多个请求时,会出现冲突的实例。这与gettimeofday()本身不准确的事实相结合,导致碰撞次数增加。我尝试使用clock_gettime,但在测试时

我的进程运行多个实例(进程)和多个线程,它们都写入同一个数据库。一旦发出请求,就会为要添加到专有数据库的记录生成唯一的req id。以下是我们的限制:长度不能超过9个字符,需要将HHMMS作为前6个字符。我们决定在最后3位使用ms来完成这9个字符,我们正在使用gettimeofday()完成所有这些操作。然而,随着通信量的增加,当在ms周期内放置多个请求时,会出现冲突的实例。这与gettimeofday()本身不准确的事实相结合,导致碰撞次数增加。我尝试使用clock_gettime,但在测试时,它也不像我从以下测试程序中观察到的那样准确:

  • 由于线程问题,我们无法使用静态或全局变量
  • 无法使用随机数,因为它们需要连续
谢谢你的帮助

#include <time.h>

int main( int argc, char **argv )
{
    long i;
    struct timespec start, stop;
    double gap;

    clock_gettime( CLOCK_REALTIME, &start);

    for (i =0; i< 123456789 ; i++);

    clock_gettime( CLOCK_REALTIME, &stop);

    gap = ( stop.tv_sec - start.tv_sec ) + ( stop.tv_nsec - start.tv_nsec ) / 1000000;
    printf( "%lf ms\n", gap );
    return 0;
}
#包括
int main(int argc,字符**argv)
{
龙我;
结构timespec启动、停止;
双间隙;
时钟获取时间(时钟实时和启动);
对于(i=0;i<123456789;i++);
时钟获取时间(时钟实时和停止);
差距=(stop.tv_sec-start.tv_sec)+(stop.tv_nsec-start.tv_nsec)/1000000;
printf(“%lf ms\n”,间隙);
返回0;
}

使用时间戳作为唯一ID将永远无法可靠工作,除非您将自己限制为每最低时钟滴答(在本例中为1毫秒)只有一个事务

由于您在9个字节中的前6个字节中使用时间值时遇到困难,因此需要尝试将尽可能多的范围放入最后3个字节中

如果您可以在最后3个字节中不使用ASCII字符,那么您应该避免使用ASCII字符,因为这将限制它可能具有的大量值。如果可能,您应该尝试将这些字节用作24位整数(范围为16777216),并让每个事务递增计数器。然后,每次gettimeofday让您知道时间已更改时,都可以将其设置回0。(或者,您可以设置一个重复的SIGALRM,让您知道何时再次调用gettimeofday来更新时间并将24位整数设为0)

如果您被迫对这些字节使用ASCII可打印字符,那么事情就有点困难了。扩展此范围的最简单方法是使用十六进制数,而不是十进制数。这将使您的代表范围从1000扩大到4096。不过,如果你使用更广泛的数字基础,你可以做得更好。如果在字母表的前22个字符上加上图钉(与十六进制在前6个字母上加图钉的方式相同),则可以表示
32x32x32
值,即32768。这将是每秒大量的事务。如果进一步扩展数字字母表,您可以做得更好,但它将变得更零碎,因为您可能希望限制某些字符出现在值中。使用
strtol
strtoul
可以轻松使用的表示法可能更易于编程


如果您的应用程序是多线程的,那么您可能需要考虑占用一部分数值范围作为线程ID,并让每个线程保持自己的事务计数器。这将使确定由不同线程处理的两个事务之间的相对时间变得更难计算,但这将避免所有线程都希望增加相同的内存位置(可能需要互斥或信号量).

在像这样的重载系统上,通常使用分辨率低于一秒的时钟时间是个坏主意。线程将占用它们的时间戳,然后在操作的中间进行调度,这样你就会看到事情出现故障。

剩下的三个字符编码的东西是唯一的不多。至少尝试使用一些不同的编码,例如base64

如果您使用
gcc
作为编译器,那么线程本地存储(TLS)作为一个非常有效的扩展。只需在
静态
变量前面加上
\u线程
(大约)。如果您仅限于phtreads,那么也可以通过
pthread\u get\u key
获取特定于线程的密钥。但最好是在线程堆栈上尽可能长地保存信息

要获取每个线程的计数器,以便为您的请求生成序列号,请使用

  • 到目前为止,您的HHMMS时间戳
  • 你需要多少就有多少 识别你的线程
  • 每个线程序列号的最后一位 如上所述,只应 一秒钟多后再绕一圈

你甚至可能会作弊,并在同一秒内产生一个引发过多请求的线程。

我想你可以在启动时给每个进程的每个线程一个唯一的ID,我想这只需要3个可用字符中的一个,除非你有数百个线程。然后,您可以使用每个线程的本地计数器来设置最后两个字符(根据允许的字符,使用base64或更多字符来获得足够的振幅)

在这种情况下,唯一可能发生冲突的情况是线程的计数器在同一秒内缠绕


当然,这是一个肮脏的黑客。正确的方法是在线程/进程之间共享ressource。在您的案例中,这可能是最简单的解决方案。

您所描述的问题类型已经通过发出UUID或多或少地得到了解决。这是一个旨在解决您提到的所有问题以及其他问题的系统

linux库:


此处提供了更多信息:

当您说字符时,您是指任何ascii字符,还是必须是最后三位数字的数字?它实际上是一个数字,但由于传统原因,它在dat中存储为9个字符的值