C ++: статические переменные в многопоточной программе - PullRequest
30 голосов
/ 04 января 2011

В чем проблема наличия статических переменных (особенно внутри функций) в многопоточных программах?

Спасибо.

Ответы [ 3 ]

28 голосов
/ 04 января 2011

Инициализация не является поточно-ориентированной. Два потока могут войти в функцию, и оба могут инициализировать статическую переменную области действия функции. Это не хорошо. Нельзя сказать, каков может быть результат.

В C ++ 0x инициализация статических переменных области действия будет поточно-ориентированной; первый поток, вызывающий функцию, будет инициализировать переменную, и любые другие потоки, вызывающие эту функцию, должны будут блокироваться до завершения этой инициализации.

Я не думаю, что в настоящее время есть какие-либо пары компилятор + стандартная библиотека, которые полностью реализуют модель памяти параллелизма C ++ 0x и библиотеки поддержки потоков и атомарности.

21 голосов
/ 04 января 2011

Чтобы случайным образом выбрать иллюстративный пример, возьмите интерфейс типа asctime в библиотеке C.Прототип выглядит так:

 char *
 asctime(const struct tm *timeptr);

Это неявно должно иметь некоторый глобальный буфер для хранения символов в возвращенном char*.Наиболее распространенным и простым способом достижения этой цели может быть что-то вроде:

 char *
 asctime(const struct tm *timeptr)
 {
    static char buf[MAX_SIZE];

    /* TODO: convert timeptr into string */

    return buf;
 }

. В многопоточной среде это полностью нарушается, потому что buf будет иметь один и тот же адрес для каждого вызова * 1012.*.Если два потока вызывают asctime() одновременно, они рискуют перезаписать результаты друг друга.В контракте asctime() подразумевается, что символы строки будут задерживаться до следующего вызова asctime(), и одновременные вызовы не нарушат этого.

Существуют некоторые языковые расширения, которые решают эту конкретную проблемув этом конкретном примере через локальное хранилище потока (__thread, __declspec(thread)).Я полагаю, что эта идея превратилась в C ++ 0x в качестве ключевого слова thread_local.

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

2 голосов
/ 04 января 2011

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

Обычно вы хотите, чтобы ваши функции были автономными; иметь локальные копии всего, с чем они работают, и ничего не делить с параметрами внешнего мира и возвращаемыми значениями. (Которые, если вы думаете определенным образом, в любом случае не являются частью функции.)

Рассмотрим:

int add(int x, int y);

определенно поточно-ориентированные локальные копии x и y.

void print(const char *text, Printer *printer);

опасно, кто-то снаружи может что-то делать с тем же принтером, например вызывая другую печать () на нем.

void print(const char *text);

определенно не поточнобезопасный, два параллельных вызова гарантированно используют один и тот же принтер.

Конечно, есть способы обеспечить доступ к общим ресурсам (ключевое слово для поиска: mutex); именно так должно быть ваше внутреннее чувство.

Несинхронизированные параллельные записи в переменную в большинстве случаев также не являются потокобезопасными, как и чтение и запись. (ключевые слова для поиска: synchronization, synchronization primitives [из которых mutex является только одним], а также atomicity / atomic operation для случаев, когда параллельный доступ безопасен.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...