|
|
  |
Хитровывернутый вопрос про RTOS, с интервью.. |
|
|
|
Jul 31 2014, 01:00
|

Местный
  
Группа: Свой
Сообщений: 414
Регистрация: 8-06-06
Пользователь №: 17 897

|
Всем привет! Недавно был на интервью в одной компании и "застрял" на вопросе про RTOS. После недели поисков ответ так и не был найден.. Условие задачи такое: есть 5 потоков, каждый из них увеличивает в цикле общую переменную count на 1. После завершения работы этих потоков, значение count выводится на экран. Код unsigned int count = 0; void thread(void) { unsigned int i; for(i = 0; i < 5; i++) { count++; } }
void main(void) { thread_create(thread, 5); // Создаём 5 экземпляров потока thread и запускаем их thread_join(); // Ждём пока все 5 потоков завершатся printf("%u", count); // Выводим значение count на экран } Внимание вопрос: почему программа печатает 2?? Договорились с интервьювером, что операция count++ состоит из 3х ассемблерных команд: Код LDR reg, count ADD reg, #1 STR reg, count Т.к. переменная count не защищена ни мьютексом, ни критической секцией, самый пессимистичный вариант, который я "раскрутил" выглядит так: Код // начало работы thread1 LDR reg, count // count = 0, thread1.reg = 0 ADD reg, #1 // thread1.reg = 1 // thread1 вытеснен планировщиком, начало работы thread2 LDR reg, count // count = 0, thread2.reg = 0 ADD reg, #1 // thread2.reg = 1 STR reg, count // count = 1 // thread2 завершил работу, управление возвращается к thread1 STR reg, count // count = 1 т.е. в результате один поток делает override результата второго потока и count = 1 после выполнения всех потоков (а не 5, как было бы с мьютексом). Но: хоть один из потоков все равно увеличит count на 1 в этой схеме, т.е. в результате работы программы count будет не меньше, чем 5. Как же получается 2? (со слов интервьювера, он наблюдал такой эффект в реальном железе). Подсказка от интервьювера: результат не зависит ни от количества потоков, ни от количества итераций в цикле for
--------------------
Курильщик даташитов со стажем
|
|
|
|
|
Jul 31 2014, 09:54
|
Профессионал
    
Группа: Свой
Сообщений: 1 214
Регистрация: 23-12-04
Пользователь №: 1 643

|
Приветствую! Скорее всего он "разводил" Вас с результатами работы программы пытаясь понять насколько Вы разбираетесь в принципах функционирования RTOS. Суда по результатам анализа - "развод" ему удался  Поскольку трудно себе представить RTOS планировщик которой работает после каждой инструкции CPU. Успехов! Rob.
|
|
|
|
|
Jul 31 2014, 15:03
|
Местный
  
Группа: Свой
Сообщений: 322
Регистрация: 2-07-04
Из: Minsk
Пользователь №: 240

|
QUOTE (gerber @ Jul 31 2014, 16:42)  Неправильно реализована функция printf на железке, а точнее stdout. В терминал отправляется правильное число 25 и приложение тут же завершается. В сдвиговый регистр (если терминал на COM-порте) только и успели положить один символ "2", и пока этот символ выдвигался в линию - приложение закрылось, закрыв за собой все открытые устройства, и терминал в том числе, очистив при этом передающий буфер. похоже. только а) принтф может стоять и тупить пока всё не отправится. б) не согласовывается с уточнением, что результат не зависит от числа потоков и величины фора. а там не 25 может получится, а и 80, к примеру.
|
|
|
|
|
Jul 31 2014, 18:09
|

Местный
  
Группа: Свой
Сообщений: 414
Регистрация: 8-06-06
Пользователь №: 17 897

|
Прошу прощения, по условиям задачи RTOS вытесняющая, процессор 32бит, count++ компилируется именно в те 3 ассемблерные команды, которые приведены и дело точно не в printf. Даже ежу понятно, что этот код никуда не годится, так не делают и т.п. Но вопрос был именно почему работа определённой программы приводит к определённому результату, шаг за шагом.. Цитата(Fat Robot @ Jul 31 2014, 15:35)  Кстати, какой результат в итоге? Сделали вам предложение? Жду..
--------------------
Курильщик даташитов со стажем
|
|
|
|
|
Jul 31 2014, 18:27
|

Местный
  
Группа: Свой
Сообщений: 414
Регистрация: 8-06-06
Пользователь №: 17 897

|
Цитата(ViKo @ Jul 31 2014, 23:17)  Для начала неплохо бы понять, в какой ОС есть функция thread_join() и как она работает. Это условная RTOS. thread_join() просто ждёт пока все потоки завершатся
--------------------
Курильщик даташитов со стажем
|
|
|
|
|
Jul 31 2014, 19:15
|
Участник

Группа: Участник
Сообщений: 73
Регистрация: 26-10-05
Пользователь №: 10 125

|
Нагло врет ваш интервьюер, если поток будет 1 все будет нормально ))))
|
|
|
|
|
Jul 31 2014, 19:57
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
99.9 % дело не вытеснении, на 32 разрядном проце каждая такая задача, уверен, успеет завершится, прежде чем будет вытеснена. Что и подтвердил мой комп - 25 ответ . Хотя код еще некорректен еще и потому, что счетчик не объявлен как volatile (а это, на самом деле, обязательно, только сегодня обсуждали на работе). Но причина вывода "2", вряд ли в этом. Хотя несколько забавно просить найти ошибку в псевдокода с псевдооперационкой. А может оператор ++ где-то переопределен как "присвоить 2" ?  Цитата(Fat Robot @ Jul 31 2014, 14:35)  Переменная count не является volatile, поэтому предположение о том, во что компилируется count++ неверно. Далее в связи с этим совершенно непонятно, во что вся эта милая конструкция превратилась после оптимизатора. Совершенно верно
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|