我目前正在处理项目,其中我使用中断来填充128个值的数组。每个中断都会顺序更新数组中的一个值。当数组已满时,会有一个短暂的延迟,然后该过程将以一批新值开始,以填充数组。问题在于我需要读取这个数组,当我在更新数组时,我不想读它。 我试图在下面的伪代码中实现这一点,但仍然存在指针可能在读取中途交换的问题。 有没有人有任何想法来实现这个目标?
int arrayA[128];
int arrayB[128];
int *readPointer;
int *writePointer;
readPointer = arrayA;
writePointer = arrayB;
void while(1) {
read();
delay(100);
}
_interrupt rx() {
static int index = 0;
*(writePointer+index) = readVal();
index++;
if(index==128) {
index = 0;
temp = writePointer;
writePointer = readPointer;
readPointer = temp;
}
}
void read() {
int myVal = anyValueInArray;
}
}
答案 0 :(得分:1)
您可以使用3个阵列。一个正在写的。一个准备好阅读。一个实际上正在阅读。当阅读器使用它的数组时,它会将其数组交换为准备读取的数组。当编写器填充数组时,它会将其数组交换为准备读取的数组。
int arrayA[128];
int arrayB[128];
int arrayC[128];
int *writePointer = arrayA;
int *readPointer = arrayB;
int *readReady = arrayC;
/* producer */
void on_interrupt () {
int is_full = fill(writePointer);
if (is_full) {
swap(writePointer, readReady);
ready_to_read_set(true);
activate_reader();
}
}
/* consumer */
void reader () {
swap(readPointer, readReady);
ready_to_read_set(false);
drain(readPointer);
}
这假设如果尚未读取已准备好读取的填充数组,则使用新填充的数组将其交换出来没有问题。
您的示例并未显示读者如何等待输入,但无论采用何种机制,都可以使用此方法进行调整,以便作者在可以读取的数组中进行交换。
答案 1 :(得分:1)
根据您需要访问数据的方式和数据速率,我可以建议五种模式(至少)。
您还可以使用两倍大小的单个缓冲区来简化中断,并简单地将读/写指针分配给该缓冲区的开头和中间。通过利用长度为2的幂,可以进一步优化中断。
#include <stdint.h>
#include <stdbool.h>
#define BUFFER_LEN (1u<<8) // Ensure a power of two
#define BUFFER_MODULO_MASK (BUFFER_LEN - 1u)
volatile int buffer_array[256];
volatile int* buffer[2] = { &buffer_array[0], &buffer_array[BUFFER_LEN / 2] ;
typedef uint8_t atomic_int_t ; // Use a type for which read/write is uninterruptable on your target
volatile atomic_int_t read_buffer_select = 1 ;
int main()
{
for(;;)
{
bool data_read = false ;
atomic_int_t current_buffer_select = read_buffer_select ;
do
{
// Read operation attempt
readfrom( buffer[current_buffer_select] ) ;
if( current_buffer_select == read_buffer_select )
{
// Read buffer consistent during read - comeplete
data_read = true ;
}
else
{
// Read bufer changed during read - try again
current_buffer_select = read_buffer_select
}
} while( !data_read ) ;
delay(100);
}
}
_interrupt rx()
{
static int index = 0;
buffer_array[index] = readVal();
index++ ;
index &= BUFFER_MODULO_MASK ;
if( index == 0 || index == BUFFER_LEN / 2 )
{
read_buffer_select == 0 ? 1 : 0 ;
}
}
如上所述,除了主循环:
for(;;)
{
// Synchronise to buffer completion
atomic_int_t current_buffer_select = read_buffer_select ;
while( current_buffer_select == read_buffer_select )
{
// do nothing
}
// Optimum time to read data
readfrom( buffer[read_buffer_select] ) ;
}
这里没有异步延迟,循环等待直到中断切换缓冲区为您提供读取和处理数据的最大时间。
同步方法具有较少的数据丢失可能性 - 如果数据丢失是一个问题,数据一致性方法依赖于延迟长度足够小以避免数据丢失但足够长以避免两次读取相同数据。除非数据丢失不是问题,否则应首选同步方法。
你当然可以将两者结合起来;同步读取然后检查读取/处理没有花费比缓冲更长的时间。这可能是不必要的 - 应该选择缓冲区长度以避免这种情况。
其他两种方法在实现中可能更复杂(但更灵活),并且在这种情况下它们是否相关并不清楚,所以我没有提供示例。