Подтвердить что ты не робот

Является ли сам прирост в потоке C безопасным?

Я нашел код в FreeRTOS (FreeRTOSV7.4.0\FreeRTOS\Source\tasks.c):

void vTaskSuspendAll( void )
{
    /* A critical section is not required as the variable is of type
    portBASE_TYPE. */
    ++uxSchedulerSuspended;
}

Явным образом сказано, что нет необходимости защищать из-за типа "portBASE_TYPE", который является "длинным" типом. Я понял, что он предполагает, что самоинстрим этого типа является атомарным. Но после того, как я разобрал его, я не смог найти никаких доказательств, это простой файл load- > add- > . Тогда это проблема?

void vTaskSuspendAll( void )
{
        /* A critical section is not required as the variable is of type
        portBASE_TYPE. */
        ++uxSchedulerSuspended;
 4dc:   4b03            ldr     r3, [pc, #12]   ; (4ec <vTaskSuspendAll+0x10>)
 4de:   f8d3 2118       ldr.w   r2, [r3, #280]  ; 0x118
 4e2:   1c50            adds    r0, r2, #1
 4e4:   f8c3 0118       str.w   r0, [r3, #280]  ; 0x118
 4e8:   4770            bx      lr
 4ea:   bf00            nop
 4ec:   00000000        .word   0x00000000

000004f0 <xTaskGetTickCount>:
        return xAlreadyYielded;
}
4b9b3361

Ответ 1

Нет, добавочные значения в C не гарантируются как атомарные. Вам необходимо обеспечить синхронизацию или использовать библиотеку, предназначенную для системы, для выполнения атомных приращений/декрементов.

Ответ 2

Это не атомный, как вы документировали. Но он все равно может быть "потокобезопасным" в менее строгом смысле: long не может находиться в противоречивом состоянии. Степень опасности здесь состоит в том, что если n потоки вызывают vTaskSuspendAll, тогда uxSchedulerSuspended будет увеличиваться где угодно между 1 и n.

Но это может быть совершенно нормально, если переменная - это то, что не обязательно должно быть совершенным, например трекер, сколько раз пользователь просил приостановить действие. Там "thread safe" означает "эта операция дает тот же результат, независимо от того, как его вызовы чередуются", и там "потокобезопасный" означает "ничего не взрывается, если вы вызываете это из нескольких потоков".

Ответ 3

Операция не является атомарной, но нигде она не говорит об этом. Тем не менее, код является потокобезопасным, но вам нужно будет хорошо знать, что делает код, и как он вписывается в дизайн планировщика, чтобы это знать. Не имеет значения, изменяют ли другие задачи переменную между загрузкой и хранилищем, потому что, когда выполняемая последующая задача запускается, она будет находить переменную в том же состоянии, что и при первоначальной загрузке (поэтому части изменения и записи по-прежнему являются согласованными и действительными).

Как и в предыдущих опубликованных заметках, long не может находиться в противоречивом состоянии, потому что это базовый тип архитектуры, на которой он запущен. Однако подумайте, что произойдет, если код будет работать на 8-битной машине (или 16 бит), а переменная будет 32 бит. Тогда он не был бы потокобезопасным, потому что полные 32 бита были бы изменены байтом или словом за раз, а не все одновременно. В этом случае один байт может быть загружен в регистр, изменен, а затем записан обратно в ОЗУ (оставив остальные три байта без модификации) при переключении контекста. Если следующая выполняемая задача прочитает одну и ту же переменную, она будет читать один байт, который был изменен, и три байта, которые не были - и у вас есть большая проблема.

С уважением, Ричард (http://www.FreeRTOS.org)