volatile int lock; main() { lock=0; create_thread(&thread1); create_thread(&thread2); {ждём и время от времени рисуем графики} } thread1() { while(1) { {что-то считаем} lock++; while(lock==1); lock=0; } } thread2() { while(1) { {что-то считаем} lock++; while(lock==1); lock=0; } }
Идея ясна: первая нить, досчитав, увеличивает lock, он становится равен 1, нить встаёт в цикл while и ждёт. Вторая нить, досчитав, увеличивает lock, он становится равен 2, нить сбрасывает lock в 0 и идёт на второй круг, первая нить, увидев 0, тоже идёт считать дальше. При желании это легко масштабируется на N нитей, заменой while(lock==1); на while(lock!=0 && lock!=N);. Да, я понимаю. что while(); грузит ядро на 100% - но разница в скорости работы нитей небольшая, да и ядро это всё равно простаивало бы, в ожидании соседней нити. Да, я знаю что "системными функциями было бы надёжнее", но нити крутятся очень быстро, вызывать относительно тяжеловесные системные функции как-то не хочется, такой вот spinlock побыстрее будет.
Так вот. После нескольких десятков-сотен тысяч "оборотов" обе нити "зависают". Зависают в while(lock==1);. Почему - я так и не понял, volatile вроде не забыл, "гонок" я не вижу. Кто-нибудь может понять, на какие грабли мы тут наступили? Компилятор - какой-то не очень свежий borland C++ builder, какой точно - на работе посмотрю, навскидку не помню.
Вопрос сейчас уже теоретический - блокировку переписали по другому, "так что работает", а поскольку задача счётная и "для себя", то и пофиг, лишь бы работало. Но чисто теоретически - какого фига? Что тут может быть, lock++ на самом деле неатомарный, или я гонки где-то не заметил?...