Преобразование однопоточного унаследованного кода с глобальными переменными в многопоточный код с использованием локального потока - PullRequest
2 голосов
/ 13 сентября 2010

У меня есть кодовая база унаследованного кода C / C ++, которая содержит множество функций, обращающихся к глобальным статическим переменным, и поэтому не является поточно-ориентированным. Я ищу совет о том, как преобразовать этот код, чтобы сделать его потокобезопасным. Мне приходит в голову, что один из способов сделать это - преобразовать статические переменные в локальные переменные потока или сохранить их в локальном хранилище. Это имеет то преимущество, что мне не нужно переписывать много кода, который использует функции для передачи им дополнительного контекста, а только сами небезопасные функции. Но, исследуя это, я не нашел много советов о том, хорошая это идея или плохая. Некоторые конкретные проблемы, которые у меня есть,

  • будет ли доступ к данным на основе TLS значительно медленнее?
  • Я просто продолжаю попадать в ловушку использования глобальных переменных, поскольку "глобальные переменные плохие" или TLS противодействует аргументу "глобальные переменные-плохие"?

Буду признателен за любые другие мысли.

Ответы [ 6 ]

2 голосов
/ 13 сентября 2010

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

После этого я уверен, что ваши проблемы только усугубятся. Я был там, где ты и мои симпатии.

1 голос
/ 13 сентября 2010

Проблема с использованием TLS заключается в том, что вы принудительно привязываете потоки к своим клиентам, и они должны знать об этом и писать свой код для соответствующей обработки.Поэтому, если у них есть рабочий поток, который выполняет тяжелую работу, им придется направить ВСЕ вызовы вашей библиотеки в этот рабочий поток, даже для простых методов получения и установки.Или, если какой-либо другой компонент вызывает их компонент в потоке пула потоков (например), им придется маршалировать этот вызов в свой рабочий поток.Это не самая плохая вещь в мире, но это может быть очень неудобно.Я определенно предпочитаю шаблон дескриптор / контекст (я поддерживаю библиотеку, которая использует TLS, и порой это была рутинная работа, связанная с привязкой потоков).

0 голосов
/ 13 сентября 2010

Вместо того, чтобы хранить все переменные в локальном потоке, я бы подумал, что лучше поместить их в класс; если исходный код был в основном C, можно обернуть код C в класс, который затем может иметь «глобальные» переменные в качестве полей. Разные экземпляры класса, работающего в разных потоках, естественно, увидят разные версии этих переменных.

0 голосов
/ 13 сентября 2010

Без понимания семантики каждой переменной, которую вы планируете преобразовать, простая автоматизация преобразования из глобального в TLS, вероятно, станет огромной непродуктивной временной потерей.Некоторые из них, возможно, должны оставаться глобальными и обрабатываться потокобезопасным способом - другие могут быть совершенно безопасны для использования в качестве TLS.Еще больше может быть поточно-ориентированным, как TLS, но приводить к плохому не масштабируемому дизайну, так как вы увеличиваете число потоков (например, один сокет на клиент / поток в ранее однопользовательском однопоточном сервере сокетов).1004 * Какая у вас платформа / компилятор здесь?

0 голосов
/ 13 сентября 2010

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

Лучший способ определить, значительно ли он медленнее, - это профилировать преобразованный фрагмент кода и посмотреть.

Как говорится, я не знаю, что это лучшее решение. Глобальные переменные - это просто так, независимо от того, как они называются, и они делают отслеживание состояния программы и отладку полным кошмаром. Я бы серьезно посоветовал внимательно взглянуть на код и реорганизовать по одному фрагменту за раз в поточно-ориентированный код, который не зависит от глобальных. Вам будет намного проще отладить время, и будущие сопровождающие (или вы сами) будете благодарны вам через несколько лет.

0 голосов
/ 13 сентября 2010

Ну, было бы довольно легко начать там.Вы можете просто иметь условную компиляцию для локального потока.Некоторые компиляторы, например, Visual Studio, имеют собственное хранилище thread_local, которое вы можете просто вставить.

...