C中的芯片8-如何正确处理延迟计时器?

C中的芯片8-如何正确处理延迟计时器?,c,linux,multithreading,emulation,chip-8,C,Linux,Multithreading,Emulation,Chip 8,TL;DR我需要在C语言中模拟一个计时器,它允许并发写入和读取,同时保持在60 Hz的恒定递减(不精确,但近似精确)。它将是Linux芯片8仿真器的一部分。使用共享内存和信号量的基于线程的方法会带来一些准确性问题,以及取决于主线程如何使用计时器的竞争条件 设计和实现这种计时器的最佳方法是什么 我正在用C语言编写一个Linux芯片8解释器,一个模块一个模块地编写,以便深入仿真世界 我希望我的实现与规范尽可能准确。在这方面,计时器已经被证明是我最困难的模块 以延迟计时器为例。在规范中,它是一个“特

TL;DR我需要在C语言中模拟一个计时器,它允许并发写入和读取,同时保持在60 Hz的恒定递减(不精确,但近似精确)。它将是Linux芯片8仿真器的一部分。使用共享内存和信号量的基于线程的方法会带来一些准确性问题,以及取决于主线程如何使用计时器的竞争条件

设计和实现这种计时器的最佳方法是什么


我正在用C语言编写一个Linux芯片8解释器,一个模块一个模块地编写,以便深入仿真世界

我希望我的实现与规范尽可能准确。在这方面,计时器已经被证明是我最困难的模块

以延迟计时器为例。在规范中,它是一个“特殊”寄存器,初始设置为0。有一些特定的操作码将值设置为,并从寄存器中获取

如果在寄存器中输入一个不同于零的值,它将以60 Hz的频率自动开始递减,一旦达到零就停止

我对其实施的想法包括以下几点:

  • 使用辅助线程,通过使用
    nanosleep()
    ,以接近60 Hz的频率自动递减。我暂时使用
    fork()
    创建线程

  • 通过
    mmap()
    使用共享内存,以便分配计时器寄存器并将其值存储在其上。这种方法允许辅助线程和主线程读取和写入寄存器

  • 使用信号量同步两个线程的访问。我使用
    sem\u open()
    创建它,使用
    sem\u wait()
    sem\u post()
    分别锁定和解锁共享资源

  • 以下代码片段说明了该概念:

    void *p = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
    /* Error checking here */
    
    sem_t *mutex = sem_open("timersem", O_CREAT, O_RDWR, 1);
    /* Error checking and unlinking */
    
    int *val = (int *) p;
    *val = 120; // 2-second delay
    
    pid_t pid = fork();
    
    if (pid == 0) {
        // Child process
        while (*val > 0) { // Possible race condition
            sem_wait(mutex); // Possible loss of frequency depending on main thread code
            --(*val); // Safe access
            sem_post(mutex);
            /* Here it goes the nanosleep() */
        }
    } else if (pid > 0) {
        // Parent process
        if (*val == 10) { // Possible race condition
            sem_wait(mutex);
            *val = 50; // Safe access
            sem_post(mutex);
        }
    }
    
    我认为这种实现的一个潜在问题依赖于第三点。如果一个程序在达到一个不同于零的值后碰巧更新了计时器寄存器,那么辅助线程不能等待主线程解锁资源,否则60 Hz延迟将无法实现。这意味着两个线程都可以自由地更新和/或读取寄存器(在辅助线程的情况下是常量写入),这显然会引入争用条件

    一旦我解释了我正在做什么以及我试图实现什么,我的问题是:


    设计和模拟允许并发写入和读取的计时器,同时保持可接受的固定频率,哪种方法是最好的方法?

    不要为此使用线程和同步原语(信号量、共享内存等)。事实上,我甚至想说:除非您明确需要多处理器并发性,否则不要将线程用于任何事情。同步很难正确进行,而且在出现错误时更难进行调试

    相反,找出一种在单个线程中实现这一点的方法。我推荐两种方法中的一种:

  • 跟踪最后一个值写入计时器寄存器的时间。当从寄存器中读取时,计算它被写入的时间,并从结果中减去适当的值

  • 跟踪总共执行了多少条指令,并每N条指令从计时器寄存器中减去1,其中N是一个大数字,因此N条指令约为1/60秒


  • +我同意这一点。让它保持单线程或包含操作系统原语,如信号,可以设置为定期触发。可用于模拟硬件定时器或systick中断。@MortenJensen不是信号。信号甚至比线程更糟糕——它们被异步调用(中断任何活动的系统调用!),而且大多数操作在信号处理程序中执行都是不安全的。这非常聪明!我想我将实现方法1。谢谢你的回复!