Синхронизация потоков со смешанным C и переполнением стека

У меня есть многопоточная программа с основным потоком, являющимся сторонним (не может изменить его) и чистым C. Моя задача состоит в том, чтобы создать вокруг него новые модули (в C ++), которые частично находятся в других потоках и должны использовать C Интерфейс программы. По сути, просто чтение некоторых переменных (целые числа, числа с плавающей запятой, ничего сложного), которые хранятся и обновляются в потоке C.

Теперь к моему вопросу: как я могу убедиться, что я не получаю мусор из интерфейса C при доступе к этим переменным, поскольку я не могу использовать мьютекс для блокировки его во время чтения. Это вообще возможно? Или в любом случае запись float / int является атомарной операцией?

4

Решение

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

Лучше всего попросить третью сторону обеспечить безопасность своей части и / или поделиться с вами механизмом блокировки.

0

Другие решения

Такие выражения, как «запись float / int [в любом случае] является атомарной операцией», к сожалению, недостаточно хорошо определены в C или C ++ (хотя с использованием std::atomic в C ++ 11 и методы stdatomic.h из C11 могут помочь здесь — но это не поможет вам с взаимодействием C для библиотеки, которую вы не можете изменить, так что вы, вероятно, можете игнорировать ее здесь).

Вы можете найти руководство по этим вопросам на конкретных компиляторах и платформах — например, вы можете выяснить, что на большинстве платформ выровненные 32-битные или 64-битные операции чтения или записи будут атомарными, если выровнены, и что большинство компиляторов будут выровнены их соответственно.

Однако по этому пути лежит безумие. Если у вас несколько потоков, просто используйте функциональность POSIX / pthreads, например pthreads мьютексы — которые легко доступны как из C, так и из C ++, для защиты любого доступа к состоянию, разделяемому между потоками.

Поскольку вы не можете изменить код C, вам, возможно, придется сделать всю блокировку в коде C ++ до любого вызова библиотеки C, после разблокировки. Если вы можете читать, но не изменять код C, или документ очень четко описывает модель потоков / совместного использования, вы можете использовать стратегию тонкозернистой блокировки, но при отсутствии какого-либо профилирования, указывающего на узкое место, я ‘ Начнем с одной глобальной блокировки, которую вы используете для защиты каждого доступа к C API.

5

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

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

3

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

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

int myVal = 0;

int main() {
while(!shouldQuit()) {
doSomeIndependentStuff();
pthread_lock(&mutex);
myVal = independentGlobalVal;
pthread_unlock(&mutex);
}
}

int getMyVal() {
int retVal = 0;
pthread_lock(&mutex);
retVal  = myVal;
pthread_unlock(&mutex);
return retval;
}
1
По вопросам рекламы [email protected]