синхронизация На работе пишем счётную программу, обсчитывающую нечто в двух нитях. Нити должны быть синхронизованы - одна не должна обгонять другую. Сделали так: ("псевдокод" на Си):
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++ на самом деле неатомарный, или я гонки где-то не заметил?...