Сравнение с обменом

Сравнение с обменом (англ. compare and set, compare and swap, CAS) — атомарная инструкция, сравнивающая значение в памяти с одним из аргументов, и в случае успеха записывающая второй аргумент в память. Поддерживается в семействах процессоров x86, Itanium, Sparc и других.

Назначение

/* Псевдокод работы инструкции, возвращающей булево значение в синтаксисе языка C */
int cas( int* addr, int old, int new )
{
  if ( *addr != old )
    return 0;

  *addr = new;
  return 1;
}

Как и другие атомарные инструкции, она предназначена для синхронизации между параллельными агентами (на разных процессорах или на одном, но без возможности монопольного захвата). Основное применение сравнения с обменом — реализация спинлоков и неблокирующих алгоритмов.

Подход атомарных инструкций противостоит подходу с «условной записью» (англ. load-link/store-conditional).

Инструкция для сравнения с обменом в процессорах x86 называется CMPXCHG и выполняется следующим образом:

  1. Процессор читает область памяти, указанную в команде первым операндом, не снимая по завершении чтения блокировку шины.
  2. Процессор сравнивает прочтённое значение со значением в аккумуляторе (регистр AL, AX, EAX или RAX). Флагу ZF присваивается значение в зависимости от результата сравнения (1 — если значение в памяти равно значению в аккумуляторе, 0 — если они различаются).
  3. Если значение в памяти было равно значению в аккумуляторе, процессор записывает значение из второго операнда в область памяти, указанную первым операндом (особенность реализации x86: запись происходит всегда, но если сравнение на шаге 2 показало неравенство, в аккумулятор записывается то значение, что было прочтено из памяти на шаге 1). По завершении записи блокировка шины снимается.

Далее программист обязан закодировать проверку флага ZF для выяснения, выполнилась операция успешно или к моменту её начала значение в памяти было заменено другим агентом.

Для SPARC инструкции для данной операции называются CASA и CASXA.

Зачем это нужно

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

На многопроцессорной же машине отключение прерываний вообще не поможет, так как в ситуации:

1-й процессор проверил, что память не заблокирована
2-й процессор проверил, что память не заблокирована
1-й процессор заблокировал память
2-й процессор заблокировал память
1-й процессор изменил память
2-й процессор изменил память
1-й процессор разблокировал память
2-й процессор разблокировал память

изменения 1-го процессора будут потеряны, а программа будет думать, что все нормально.

Пример использования

У нас есть n процессоров, каждый из которых иногда хочет получить доступ к какому-то общему ресурсу. Например, к устройству или общему участку памяти.

До начала основной работы назначим им уникальные номера от 0 до n-1.

Выберем ячейку памяти, которая будет указывать, какой процессор сейчас использует ресурс. Значение −1 будет указывать, что ресурс никем не занят. Поместим в неё −1.

При основной работе каждый процессор должен проверить, что в ячейке находится −1, и если это так, то записать в неё свой номер. Если же ячейка занята — процессор обязан ждать, пока она не освободится (мы договорились, что он будет ждать, и не будем писать программы, которые не выполняют это требование).

То есть программа может выглядеть следующим образом:

; блокировка
m_wait:
mov eax, -1
mov ecx, 5               ; номер нашего процессора 5
cmpxchg 105BA9D2, ecx    ; адрес ячейки 105BA9D2
jnz m_wait ; если ресурс заблокирован
; работа с общим ресурсом
...

; снятие блокировки
...

Использование в языках C/C++

Инструкции атомарного сравнения с обменом не входили в стандарты языков C/C++, поэтому они либо реализуются через ассемблер, либо через нестандартные расширения языка. В стандарте C++11 введена библиотека атомарных операций, в которой есть сравнение с обменом[1]. Также существует несколько библиотек с реализациями C/C++ интерфейсов к подобным инструкциям, например: Intel TBB, boost.atomic, Open Portable Atomics, Glib.

Через ассемблерную вставку

Команду cmpxchg напрямую можно закодировать с помощью следующей ассемблерной вставки компилятора GCC (GCC Inline Assembly):

uint32_t* ptr;
uint32_t ret_val, old_val, new_val;

asm volatile("lock\n\tcmpxchgl %1,%2"
  : "=a"(ret_val)
  : "r"(new_val), "m"(*ptr), "0"(old_val)
  : "memory"
  );

либо для x86-64:

uint64_t* ptr;
uint64_t ret_val, old_val, new_val;

asm volatile("lock\n\tcmpxchgq %1,%2"
  :"=a"(ret_val)
  :"r"(new_val), "m"(*ptr), "0"(old_val)
  :"memory"
  );

Следует обратить особое внимание на то, что используется asm volatile (а не просто asm), инструктирующая оптимизирующий компилятор о том, что у данной ассемблерной вставки есть побочные эффекты, и она должна находиться в том месте цикла, где находится по коду. Также обязательным является указание «memory» в clobbering list.

Через встроенные функции

GCC и некоторые другие компиляторы поддерживают builtin-расширения для реализации этой инструкции:

TYPE __sync_val_compare_and_swap(TYPE* ptr, TYPE oldval, TYPE newval);

Данное расширение может быть реализовано не для всех поддерживаемых gcc архитектур либо не во всех версиях gcc.[2]

Подобные функции с другим именем существуют в компиляторах для ОС Windows и Mac OS X: InterlockedCompareExchange(), OSAtomicCompareAndSwapPtrBarrier().

Безблокировочные алгоритмы с детектированием коллизий

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

Рассмотрим такой участок псевдокода:

читаем значение переменной;
производим некоторую обработку;
записываем новое значение переменной;

Наиболее обычным способом сделать данный код многопоточным является введение синхронизирующих примитивов (mutex'ы, спинлоки, и т. д.) следующим образом:

производим блокировку;
читаем значение переменной;
производим некоторую обработку;
записываем новое значение переменной;
отпускаем блокировку;

Однако, зачастую применим более элегантный метод:

читаем значение переменной;
производим некоторую обработку;
производим cmpxchg новое значение переменной в предположении что значение все еще равно старому;
если значение было изменено другим потоком - повторяем обработку;

Реальный пример безблокировочного алгоритма и производительность

Рассмотрим классический пример структуры данных — связный список.

struct ll_node {
  int key; // некоторый ключ
  int val; // некоторое значение
  struct ll_node* next; // указатель на следующий
};

Функция вставки в связанный список узла new_node после указанного узла node выглядит следующим образом:

 void ll_insert_after(struct ll_node* node, struct ll_node* new_node)
 {
   new_node->next = node->next;
   node->next = new_node; // (!!!) - обратим внимание на данную строку
 }

Очевидно, код будет работать корректно только в предположении, что значение node->next не было изменено другим потоком к моменту работы строки, отмеченной «(!!!)», в противном случае мы рискуем потерять изменения остальных потоков, породив узлы, не относящиеся к списку (Утечка памяти).

Существует 3 основных способа борьбы с этим:

1) Закрыть весь связный список мьютексом. С точки зрения производительности, это самый худший способ. Во-первых, со связным списком в данный момент времени будет работать только один поток, что само по себе сводит на нет все плюсы многопоточности. Во вторых, на практике ситуация обстоит намного хуже, чем можно было бы предположить: более-менее интенсивная одновременная работа с таким связным списком будет порождать огромное (тысячи, десятки тысяч, а в отдельных, особо интенсивных случаях даже миллионы) переключений контекста, что само по себе способно убить производительность не только самого приложения, но и системы в целом (эффект «просаживания производительности» квадратично возрастает от числа вычислительных ядер).

2) Более интеллектуальный способ. Заменить Mutex на спинлок. Несколько холостых циклов ожидания занятости обходятся намного «дешевле», чем системный вызов и порожденное им переключение контекста. Дает реальный эффект на SMP-системах, однако на одноядерных системах порождает «редкий, но меткий» убой производительности за счет длительного простоя.

3) Алгоритм без блокировки. Перепишем функцию вставки следующим образом: сделаем предположение о неизменности значения node->next явным. Его мы в явном виде и будем проверять с помощью команды cmpxchg:

 void ll_insert_after(struct ll_node* node, struct ll_node* new_node)
 {
   struct ll_node* old_val = node->next; // запоминаем старое значение
   while (1) {
     new_node->next = old_val;
     old_val = cmpxchg(&node->next, old_val, new_node);
     if (old_val == new_node)
       break; // Другие потоки не меняли node->next. Успех операции, выход.
     // Иначе повторим попытку
   }
 }

«Ядром» безблокировочной логики данной функции служит команда CMPXCHG. Она атомарно проверяет, что содержимое ячейки памяти &node->next все еще содержит значение old_val, и если это так (а вероятность этого лучшего случая крайне высока), записывает значение указателя new_node и выходит из цикла. В случае коллизии совместного доступа мы получаем обновленное значение old_val и выходим на новую итерацию цикла.

В случае рассматриваемого выше связного списка вероятность коллизии крайне мала. Формально она равна Pкол=(n/N)*pфунк , где N — к-во записей в списке, n — к-во одновременных потоков, pфунк — отношение времени, которое каждый поток проводит внутри функции вставки, к общему времени работы потока.

Команды CMPXCHG8B, CMPXCHG16B

Главным недостатком, сдерживающим применение команды cmpxchg в безблокировочных алгоритмах, состоит в том, что команда заменяет всего лишь одно значение. В случае, когда это только значение указателя или целочисленная переменная, этого достаточно. Однако, очень часто требуется атомарно условно заменить две связанные переменные. Например: указатель на буфер и его длину, указатель на начало и конец данных и т. д. Для этих целей в процессорах Intel введены команды CMPXCHG (32-bit), CMPXCHG8B (64-bit) и CMPXCHG16B (x86 64). Кстати, требование поддержки процессором команды CMPXCHG16B появилось в ОС MS Windows версии 8.1 x64.

В процессорах SPARC эти функции выполняют команды CASA и CASXA.

См. также

Примечания

  1. std::atomic_compare_exchange_weak, std::atomic_compare_exchange_strong, std::atomic_compare_exchange_weak_explicit, std::atomic_compare_exchange_strong_explicit - cppreference.com. en.cppreference.com. Дата обращения: 10 ноября 2015. Архивировано 3 ноября 2015 года.
  2. 5.44 Built-in functions for atomic memory access Архивная копия от 24 сентября 2011 на Wayback Machine, «Not all operations are supported by all target processors. … type __sync_val_compare_and_swap (type *ptr, type oldval type newval, …)»

Ссылки

Read other articles:

Southern District Recreation & Sports Assn Ltd (Hanzi: 南 區 足球 會), umumnya dikenal sebagai Southern District FC dan saat ini dikenal karena alasan sponsor sebagai Kwoon Chung Selatan , adalah klub sepak bola yang berbasis di Distrik Selatan, Hong Kong. Mereka saat ini berkompetisi di Liga Utama Hong Kong. Southern DistrictNama lengkapSouthern District Recreation & Sports Assn LtdJulukanThe AberdeenersBerdiri2002StadionAberdeen Sports Ground(Kapasitas: 4,500)PresidentMatth...

 

Iglesia de San Nicolás LocalizaciónPaís AzerbaiyánDivisión BakúDirección BakúCoordenadas 40°23′43″N 49°52′56″E / 40.39527778, 49.88222222Información religiosaCulto Iglesia ortodoxa rusaAdvocación Nicolás de BariFundación 1857Demolición 1930Datos arquitectónicosTipo Iglesia desaparecidaAforo 500Altura 45 mMapa de localización Iglesia de San Nicolás (Bakú) Mapa[editar datos en Wikidata] La Iglesia de San Nicolás (en idioma ruso: Собор ...

 

Argentine footballer Ubaldo Fillol Fillol as displayed in a 1978 Panini cardPersonal informationFull name Ubaldo Matildo FillolDate of birth (1950-07-21) 21 July 1950 (age 73)Place of birth San Miguel del Monte, Buenos Aires, ArgentinaHeight 1.81 m (5 ft 11+1⁄2 in)Position(s) GoalkeeperSenior career*Years Team Apps (Gls)1965–1971 Quilmes 57 (0)1971–1973 Racing Club 59 (0)1973–1983 River Plate 360 (0)1983–1984 Argentinos Juniors 17 (0)1984–1985 Flamengo 34 (...

قصر تنغراس تقسيم إداري البلد المغرب  الجهة درعة تافيلالت الإقليم الرشيدية الدائرة الريصاني الجماعة القروية السفلات المشيخة الثلث الوسطاني السكان التعداد السكاني 1431 نسمة (إحصاء 2004)   • عدد الأسر 183 معلومات أخرى التوقيت ت ع م±00:00 (توقيت قياسي)[1]،  وت ع م+01:00 (توقيت ...

 

Artikel atau sebagian dari artikel ini mungkin diterjemahkan dari corona discharge di en.wikipedia.org. Isinya masih belum akurat, karena bagian yang diterjemahkan masih perlu diperhalus dan disempurnakan. Jika Anda menguasai bahasa aslinya, harap pertimbangkan untuk menelusuri referensinya dan menyempurnakan terjemahan ini. Anda juga dapat ikut bergotong royong pada ProyekWiki Perbaikan Terjemahan. (Pesan ini dapat dihapus jika terjemahan dirasa sudah cukup tepat. Lihat pula: panduan penerje...

 

شركة القاهرة للعبارات والنقل البحريالشعارمعلومات عامةالجنسية  مصرالتأسيس 2009 (منذ 14 سنة)النوع شركة مساهمةالمقر الرئيسي سفاجا،  مصرموقع الويب kcfmt.comالمنظومة الاقتصاديةالنشاط نقل بحريأهم الشخصياتالمالك وزارة النقلالرئيس وائل محمد عبد الخالق[1]الإيرادات والعائدا...

Censored blurring used in photos & film Image in which people's faces have been fogged or blurred out Fogging, also known as blurring, is used for censorship or privacy. A visual area of a picture or movie is blurred to obscure it from sight. This form of censorship is used for sexually related images/scenes, hiding genitals, pubic hair, or sexual penetration of any sort. Pixelization is a form of fogging. In Japan, where it is called bokashi, fogging is employed on most films aired on pu...

 

This article needs additional citations for verification. Please help improve this article by adding citations to reliable sources. Unsourced material may be challenged and removed.Find sources: Garden Route – news · newspapers · books · scholar · JSTOR (March 2014) (Learn how and when to remove this template message) For the municipality that includes the Garden Route, see Garden Route District Municipality. Map showing the Garden Route's location The...

 

American singer (born 1992) Demi LovatoLovato at the 2023 MTV Video Music AwardsBornDemetria Devonne Lovato (1992-08-20) August 20, 1992 (age 31)Albuquerque, New Mexico, U.S.OccupationsSingersongwriteractressYears active2002–present[1]WorksDiscographysongs recordedvideographyperformancesRelativesMadison De La Garza (half-sister)Francisco Perea (great-great-great-grandfather)AwardsFull listMusical careerGenresPop[2]rock[3]R&B[4][5]Instrum...

Irish journalist and former politician Susan O'KeeffeO'Keeffe in 2014SenatorIn officeApril 2011 – April 2016ConstituencyAgricultural Panel Personal detailsBorn (1960-09-18) 18 September 1960 (age 63)Dublin, IrelandPolitical partyLabour PartyProfessionJournalist Susan O'Keeffe (born 18 September 1960) is an Irish journalist and former Labour Party politician.[1][2] Personal life She was educated at Mount Anville Secondary School, Dublin, and at University Colleg...

 

Artikel ini tidak memiliki referensi atau sumber tepercaya sehingga isinya tidak bisa dipastikan. Tolong bantu perbaiki artikel ini dengan menambahkan referensi yang layak. Tulisan tanpa sumber dapat dipertanyakan dan dihapus sewaktu-waktu.Cari sumber: Gampong Lada, Mutiara Timur, Pidie – berita · surat kabar · buku · cendekiawan · JSTOR Gampong Lada adalah sebuah gampong di Kemukiman Alue Batee, Kecamatan Mutiara Timur, Kabupaten Pidie, Aceh.[1 ...

 

Subscription library in Newport, Rhode Island, United States Redwood LibraryThe building's façadeLocationNewport, Rhode IslandTypeSubscription libraryEstablished1747 (1747)Access and useCirculation15,204 (2018)[1]Other informationDirectorBenedict Leca, Ph.D. FRSA[2]Websitewww.redwoodlibrary.orgRedwood LibraryU.S. National Register of Historic PlacesU.S. National Historic LandmarkU.S. National Historic Landmark DistrictContributing Property Location50 Bellevue Avenue, New...

American football team Chicago Athletic Association building. The Chicago Athletic Association was an American football team, based in Chicago, Illinois. The club itself had been organized in 1890, and in 1892 it formed a football team. The team was built around veterans of Chicago's University Club football team. History The University Club football team was the initial first-rate team produced by the city, because Illinois and Northwestern were still years away from being competitive, and A...

 

This article needs additional citations for verification. Please help improve this article by adding citations to reliable sources. Unsourced material may be challenged and removed.Find sources: Velika Gorica – news · newspapers · books · scholar · JSTOR (September 2009) (Learn how and when to remove this template message) City in Zagreb, CroatiaVelika GoricaCityGrad Velika GoricaCity of Velika GoricaFrom top left: Vodotoranj (Water Tower Building), Me...

 

Protected area in Maryland, United States Savage River State ForestView of Savage RiverLocationGarrett County, Maryland, United StatesNearest cityGrantsville, MDCoordinates39°35′59.4″N 79°3′17″W / 39.599833°N 79.05472°W / 39.599833; -79.05472Area54,000 acres (220 km2)[1]EstablishedJanuary 8, 1929[2]Governing bodyDepartment of Natural Resourceswww.dnr.state.md.us Savage River State Forest is located in the north and northeaster...

City in Baja California, Mexico City and municipality in Baja California, MexicoEnsenada, Baja CaliforniaCity and municipality Top: view of Ensenada from the Pacific; middle: Riviera del Pacífico Cultural Center (left), Downtown Ensenada (right); bottom: Ensenada’s Pacific Coast (left) and Cathedral of Our Lady of Guadalupe (right). FlagCoat of armsNicknames: Cenicienta del Pacífico(Cinderella of the Pacific)EnsenadaLocation in MexicoShow map of Baja CaliforniaEnsenadaEnsenada (Mexic...

 

Common name of several species of fungi For other uses, see Chanterelle (disambiguation). One of several species called chanterelle (Cantharellus cibarius) Chanterelle is the common name of several species of fungi in the genera Cantharellus, Craterellus, Gomphus, and Polyozellus. They are among the most popular of wild edible mushrooms. They are orange, yellow or white, meaty and funnel-shaped. On the lower surface, underneath the smooth cap, most species have rounded, forked folds[1]...

 

Speed that exceeds the speed of sound Supersonic redirects here. For other uses, see Supersonic (disambiguation). A United States Navy F/A-18F Super Hornet in transonic flight U.S. Navy F/A-18 approaching the sound barrier. The white cloud forms as a result of the supersonic expansion fans dropping the air temperature below the dew point.[1][2] Supersonic speed is the speed of an object that exceeds the speed of sound (Mach 1). For objects traveling in dry air of a temper...

Canadian ice hockey player (born 1986) Ice hockey player Derek Dorsett Dorsett with the Columbus Blue Jackets in 2010Born (1986-12-20) December 20, 1986 (age 36)Kindersley, Saskatchewan, CanadaHeight 6 ft 0 in (183 cm)Weight 192 lb (87 kg; 13 st 10 lb)Position Right wingShot RightPlayed for Columbus Blue JacketsNew York RangersVancouver CanucksNHL Draft 189th overall, 2006Columbus Blue JacketsPlaying career 2007–2017 Derek Dorsett (born December 2...

 

جزء من سلسلة مقالات حولعسكرية السعودية الإدارات مجلس الخدمة العسكرية الدفاع الحرس الوطني الداخلية الدائرة العسكرية الجهاز العسكري رئاسة الحرس الملكي رئاسة أمن الدولة رئاسة الاستخبارات العامة القوات القوات المشتركة القوات البرية القوات البحرية الحرس الملكي الحرس الوطن...

 

Strategi Solo vs Squad di Free Fire: Cara Menang Mudah!