C中的芯片8-如何正确处理延迟计时器?
TL;DR我需要在C语言中模拟一个计时器,它允许并发写入和读取,同时保持在60 Hz的恒定递减(不精确,但近似精确)。它将是Linux芯片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解释器,一个模块一个模块地编写,以便深入仿真世界 我希望我的实现与规范尽可能准确。在这方面,计时器已经被证明是我最困难的模块 以延迟计时器为例。在规范中,它是一个“特
我正在用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延迟将无法实现。这意味着两个线程都可以自由地更新和/或读取寄存器(在辅助线程的情况下是常量写入),这显然会引入争用条件
一旦我解释了我正在做什么以及我试图实现什么,我的问题是:
设计和模拟允许并发写入和读取的计时器,同时保持可接受的固定频率,哪种方法是最好的方法?不要为此使用线程和同步原语(信号量、共享内存等)。事实上,我甚至想说:除非您明确需要多处理器并发性,否则不要将线程用于任何事情。同步很难正确进行,而且在出现错误时更难进行调试 相反,找出一种在单个线程中实现这一点的方法。我推荐两种方法中的一种:
+我同意这一点。让它保持单线程或包含操作系统原语,如信号,可以设置为定期触发。可用于模拟硬件定时器或systick中断。@MortenJensen不是信号。信号甚至比线程更糟糕——它们被异步调用(中断任何活动的系统调用!),而且大多数操作在信号处理程序中执行都是不安全的。这非常聪明!我想我将实现方法1。谢谢你的回复!