Является ли мой скетч «потокобезопасным»?
Я работаю с .Net. Обычно я "блокирую" операции с целыми числами, когда у меня есть требования к потокобезопасности. Я не уверен, что это относится к моему скетчу здесь? Могу ли я обойти приращение одного из моих контактов прерывания?
Подводя итог, у меня есть 2 контакта прерывания - я хочу увеличить счетчик, который (каждые 5 секунд) записывает через последовательный порт и сбрасывает.
Я делаю это, чтобы избежать записи серийного номера из прерывания — поскольку я читал, что это настоятельно не рекомендуется.
#include <Controllino.h>
const byte interruptPin0 = CONTROLLINO_IN0;
const byte interruptPin1 = CONTROLLINO_IN1;
int counter1 = 0;
int counter2 = 0;
unsigned long previousMillis = 0;
unsigned long interval = 5000;
int a = 60;
char buffer[256];
void setup()
{
pinMode(interruptPin0, INPUT_PULLUP);
pinMode(interruptPin1, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin0), pin1Fired, RISING);
attachInterrupt(digitalPinToInterrupt(interruptPin1), pin2Fired, RISING);
Serial.begin(9600);
}
void loop()
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
sprintf(buffer,"A%d",counter1);
Serial.println(buffer);
sprintf(buffer,"D%d",counter2);
Serial.println(buffer);
counter1 = counter2 = 0;
}
}
void pin1Fired()
{
counter1++;
}
void pin2Fired()
{
counter2++;
}
@JᴀʏMᴇᴇ, 👍1
1 ответ
Лучший ответ:
В вашем коде действительно есть состояние гонки: если срабатывает прерывание пока вы читаете один из счетчиков, вы можете прочитать мусор. Если оно срабатывает между чтением и сбросом счетчика, вы теряете один счет.
Чтобы предотвратить гонку, нужно заблокировать прерывания, пока основной поток
(все, что не выполняется в контексте прерывания) обращается к
счетчики. Кстати, не забудьте сделать счетчики volatile
.
Части кода, которые выполняются с отключенными прерываниями, называются «критические разделы», и вы должны сделать их как можно короче в чтобы ограничить задержку прерывания, которую они вводят. Как правило, в пределах эти критические разделы вы не делаете ничего, кроме доступа к общему переменные. Пример:
void loop()
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
noInterrupts(); // начало критической секции
int counter1Copy = counter1;
counter1 = 0;
interrupts(); // конец критической секции
Serial.print("A");
Serial.println(counter1Copy);
noInterrupts(); // начало критической секции
int counter2Copy = counter2;
counter2 = 0;
interrupts(); // конец критической секции
Serial.print("D");
Serial.println(counter2Copy);
}
}
- Отправка последовательных данных в прерывании
- Серийное прерывание
- Несколько независимых шаблонов светодиодов
- Есть ли способ использовать последовательный порт в качестве источника прерывания?
- Можно ли безопасно использовать последовательный порт в процедуре прерывания SPI?
- Простое последовательное сообщение непоследовательно (иногда перемешано)
- Целесообразно ли использовать Serial.write в ISR, когда loop() обычно использует Serial.read?
- Как соединить автономный многоканальный adc с последовательным?
Отличный! Большое спасибо за это, вероятно, избавил меня от многих хлопот, когда дело дошло до пропущенных счетов! Только один вопрос - в то время, когда прерывания запрещены (?) - мы не уязвимы к отсутствию обработчиков прерываний? т.е. все еще отсутствуют подсчеты?, @JᴀʏMᴇᴇ
Когда прерывание происходит в это время, оно будет выполнено после того, как вы снова включите прерывания. Вы только потеряете счет, когда за это время произойдет 2 или более прерываний. Чтобы предотвратить это, вам нужно, чтобы отключенное время было ниже, чем время между двумя прерываниями., @chrisl
@chrisl прав. Чтобы быть более конкретным, вы теряете счет, если 2 или более экземпляров _одного и того же прерывания_ срабатывают в течение этого окна. Если вы получаете один INT0 и один INT1, все в порядке., @Edgar Bonet
Понял, блестяще объяснил. Спасибо Эдгар., @JᴀʏMᴇᴇ