Как написать «потокобезопасную» функцию в C? - PullRequest
1 голос
/ 03 апреля 2010

Здравствуйте, я пишу некоторые структуры данных на C, и я понял, что их связанные функции не являются потокобезопасными. Я пишу код использует только стандарт C, и я хочу добиться какой-то «синхронизации».

Я думал сделать что-то вроде этого:

enum sync_e { TRUE, FALSE };
typedef enum sync_e sync;


struct list_s {
//Other stuff
    struct list_node_s *head;
    struct list_node_s *tail;
    enum sync_e locked;
};
typedef struct list_s list;

, чтобы включить в структуру списка «логическое» поле, которое указывает состояние структур: заблокировано, разблокировано.

Например, функция вставки будет переписана следующим образом:

int list_insert_next(list* l, list_node *e, int x){
    while(l->locked == TRUE){
        /* Wait */
    }
    l->locked = TRUE;
    /* Insert element */
    /* -------------- */
    l->locked = FALSE;
    return (0);
}

При работе со списком в поле «заблокировано» будет установлено значение ИСТИНА, не допускающее никаких других изменений. После завершения операции «заблокированное» поле снова будет установлено на «ИСТИНА».

Этот подход хорош? Знаете ли вы другие подходы (используя только стандарт C).

Ответы [ 5 ]

5 голосов
/ 03 апреля 2010

Стандартный C ничего не «знает» о потоках. Все потоки, связанные как сами потоки, примитивы синхронизации, атомарные операции, не являются частью языка или стандартной библиотеки. Они всегда являются частью системных библиотек, таких как POSIX или Windows API.

Поэтому невозможно защитить вашу структуру данных от состояния гонки, когда она используется несколькими потоками, использующими только стандартный C.

Если экземпляр вашей структуры используется только одним потоком, он может использоваться в многопоточном сценарии, как, например, вы. не используйте статические переменные внутри ваших функций.

3 голосов
/ 03 апреля 2010

Ваш код может вызвать race condition. Вы должны использовать мьютекс для этого.

1 голос
/ 03 апреля 2010

Принцип в порядке, в зависимости от вашей платформы. Если у вас очень простой процессор и ресурс распределяется между двумя подпрограммами прерывания, этого может быть достаточно.

Вы должны быть осторожны с условиями гонки и инверсией приоритетов, посмотрите.

1 голос
/ 03 апреля 2010

Нет гарантии, что

l->locked = TRUE;

произойдет мгновенно в течение одной атомарной операции. Он может быть скомпилирован в несколько инструкций процессора (зависит от архитектуры процессора, компилятора, операционной системы и т. Д.)

Вы должны использовать механизмы синхронизации, предоставляемые вашей средой. Это выходит за рамки стандарта C.

1 голос
/ 03 апреля 2010

К сожалению, я не думаю, что Ansi C предоставляет мьютекс-механизм ... также он не обеспечивает механизм многопоточности.

Если вы хотите получить многопоточный код, который можно переносить, вы можете выбрать набор примитивов, например posix . Конечно, это переносимо только в системах Unix. Так что, если вам нужно предложение, вы должны программировать на какую-то высокоуровневую библиотеку с обертками потоков и мьютексами на разных системах. Я думаю, что glib должен делать то, что вам нужно.

...