На одном ядре - DOS, на втором супервайзер.
суперкластер ага)
тогда уж вин95
начать с win 3.1
если по честному тогда уж с win 2.0
Вопрос к поднаторевшим: Корректно ли использовать в качестве семафора использовать булеву volatile переменную в многопоточной обработке во избежания коллизий при доступе к переменной. Пример в коде:
/// Осциллоскоп ¯\_(ツ)_/¯
#include <GyverOLED.h>
GyverOLED<SSH1106_128x64> oled;
volatile uint16_t sensorValue;
volatile bool fBuzy = false;
void setup() {
Serial.begin(115200);
}
void loop() {
uint16_t tempVal;
tempVal = analogRead( A0);
fBuzy^=true; // установить флаг занятости
sensorValue = tempVal;
fBuzy^=true; // сбросить флаг занятости
Serial.println(sensorValue);
delay(1);
}
void setup1() {
oled.init();
Wire.setClock( 1200000L);
}
void loop1() {
uint16_t tempVal;
uint16_t prevVal;
oled.clear();
prevVal = 0;
for (byte x = 0; x < 128; x++) {
while ( fBuzy);
tempVal = sensorValue;
tempVal = (tempVal - 200)<<1;
oled.line( x, prevVal, x+1, tempVal, x?1:0);
//oled.dot( x, tempVal, 1);
prevVal = tempVal;
delay(1);
}
oled.update();
}
А переводить volatile не пробовал перед тем как задать вопрос вопрос?
Идея состояла в использовании не оптимизированной булевой переменной в качестве семафора с изменением её атомарной операцией XOR…
В общем то, работать это будет, если судить по обсуждению на c++ - When to use volatile with multi threading? - Stack Overflow. Но не рекомендуется…
Кем?
bool, сдается мне, тут излишен. Может из-за этого и не работает :0)
С++ сгенерирует 2 переменные, setSDA = false и setSCL = true. Это то, что нужно?
Проблема вот какая: цикл работы с переменной обычно выглядит так:
- добыть переменную из памяти в регистр
- совершить ту или иную операцию (например ++)
- сохранить новое значение в память.
Если у тебя многопоточность, то будет происходить следующее:
Thread1: достал переменную, прибавил единицу, и…
Случился Context Switch
Thread2: достал переменную, прибавил единицу, сохранил, и…
Случился Context Switch
Thread1 сохранил свой вариант.
Как видно, один из инкрементов потеряется. Дела будут еще хуже на многоядерной системе: два ядра одновременно будут писать, например, в 32-битную переменную, и там будет совсем мусор.
ЗЫЖ
Посмотрел повнмательнее: твой вариант пойдет. У тебя только одна задача пишет в переменную.
Есть такие хрени, как семафор, ATOMIC_BLOCK и еще одна, на LOCK… начинается, забыл.
Upd. CRITICAL_SECTION
Это все в полноценных ОС есть, а тут все ручками надо придумывать на PICO.
Хотя давно это было, но вроде в PICO в даташите что то было про корректную работу в многпоточности
Разве FreeRTOS на него не портирован?
Без понятия. Для меня Free RTOS это какашка. Впрочем дело вкуса.
Тащемта мы об \том и говорим.. Вопрос был - “можно ли использовать volatile для того, чтобы работало, как семафор.”
Короткий ответ: в общем случае -нет.
Частный случай, как в посте автора - ответ: да, скорее всего это сработает.
spinlock.
на его основе, в принципе, все остальные примитивы (семафоры, мутексы) и строятся.
PS: не знаю насчет Пико, но думаю,что там все с этим хорошо..
С этим - atomic_compare_xchange.
В Интеле есть отдельная ассемблерная инструкция cmpxchg. Очень удобно делать всякие синхронизационные примитивы.
А в ESP32 этого нет.
Может быть плохо искал.
Но там, честно говоря, чорт ногу сломит: более отвратительного даташита, чем Xtensa ISA я в жизни не видывал. Это такая эзотерика,что атас.
можно стырить из RTEMS или FreeRTOS. Мне первая как-то ближе. Ну или из linux/arch/какой-там-процессор-в-пико
почитайте как работает например семафоры или распределенная память
обязательно почитать еще стетейку как это все использовать в Linux своих программах на Си.
и подумайте можно ли это перетащить в Pico…
во нашел в документации PICO, наверное проще программе точно узнавать на каком ядре она конкретно сейчас работает и уже логику написать для корректного обмена с общими переменными или областью памяти.
Спойлер
#include <stdio.h>
2 #include "pico/stdlib.h"
3 #include "pico/multicore.h"
4
5 #define FLAG_VALUE 123
6
7 void core1_entry() {
8
9 multicore_fifo_push_blocking(FLAG_VALUE);
10
11 uint32_t g = multicore_fifo_pop_blocking();
12
13 if (g != FLAG_VALUE)
14 printf("Hmm, that's not right on core 1!\n");
15 else
16 printf("Its all gone well on core 1!");
17
18 while (1)
19 tight_loop_contents();
20 }
21
22 int main() {
23 stdio_init_all();
24 printf("Hello, multicore!\n");
25
26
27 multicore_launch_core1(core1_entry);
28
29 // Wait for it to start up
30
31 uint32_t g = multicore_fifo_pop_blocking();
32
33 if (g != FLAG_VALUE)
34 printf("Hmm, that's not right on core 0!\n");
35 else {
36 multicore_fifo_push_blocking(FLAG_VALUE);
37 printf("It's all gone well on core 0!");
38 }
39
40 }
Там-то все просто: pthreads, POSIX стандарт.