Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
struct node { node* next; };
struct queue
{
node *head, *tail;
// это пример wait-free алгоритма, операция завершается
// за известное заранее число инструкций
void put(node* n) {
n->next=0;
atomic_swap(tail, n);
if(n) n->next=tail;
}
// это lock-free, но не wait-free алгоритм,
// мы крутимся в цикле пока операция не пройдет успешно
node* get() {
for(;;) {
node *n=head;
if(atomic_compare_and_swap(head, n, n->next))
return n;
}
}
};
Spin locks and other algorithms with busy-wait loops are not lock-free
Да, да, все локальные для данного потока переменные размещаются в thread local storage и никакими силами нельзя заставить другой поток увидеть их адрес.
Если залезть под капот (разумеется я не мог не заглянуть), увидим что код совершенно обычный — односвязные списки защищенные мьютексами.Там ещё и сообщения полиморфные, то есть можно послать что угодно кому угодно, а тому придётся разгребать. Лучше всего для обмена сообщениями между потоками подходят каналы, как в go. Вот моя реализация неблокирующих каналов на D. Там, правда, используется экспоненциальное засыпание, а не блокирующая переменная, и не хватает мультиплексирования волокон, которые позволяют вместо засыпания, заняться потоку чем-то полезным.
import std.stdio, std.datetime, jin.go;
struct Tick { long start; }
struct Ask {}
enum N = 1000000;
void main() {
auto ticks = new Queue!Tick;
auto asks = new Queue!Ask;
start!f( ticks , asks );
foreach( i ; 0 .. N ) {
ticks.push!Tick( MonoTime.currTime.ticks );
asks.take;
}
}
void f( Queue!Tick ticks , Queue!Ask asks ) {
foreach( i ; 0 .. N ) {
auto m = ticks.take.start;
writeln( MonoTime.currTime.ticks - m );
asks.push!Ask();
}
}

iBolit# cat /sys/devices/system/clocksource/clocksource0/available_clocksource
tsc hpet acpi_pm
iBolit# cat /sys/devices/system/clocksource/clocksource0/current_clocksource
tsc
Передача сообщений между потоками. Классические блокирующие алгоритмы