Мазмунга өтүү

Сабактын башталышы

Көп агымдуулук

Кодду коопсуз параллель аткаруу: агымдар, мьютекстер, шарттуу өзгөрмөлөр жана өз ара бөгөттөөдөн качуу

Негизги ой: Агым (thread) - бул бир процесстин ичиндеги көз карандысыз аткаруу агымы. Бардык агымдар бир дарек мейкиндигин бөлүшөт - ошол эле глобалдык өзгөрмөлөрдү, ошол эле үймөктү (heap) - жана дал ушул агымдарды бир эле убакта күчтүү да, коркунучтуу да кылат. Бөлүшүү агымдарга арзан кызматташууга мүмкүндүк берет; ошол эле учурда эки агым бир маалыматка бир убакта тийсе, аны бузуп коюшу мүмкүн. Заманбап C++ (C++11ден баштап, C++17 жана C++20до өркүндөтүлгөн) көчмө агым китепканасын берет, ошондуктан pthreads же Win32 агымдары сыяктуу платформага байланыштуу API'лер мындан ары керек эмес.
Аягында сиз буларды жасай аласыз:
  • ишти std::threadто баштоо жана анын жашоо мөөнөтүн join/detach аркылуу башкаруу - жана C++20дун std::jthreadин артык көрүү;
  • маалымат жарышы деген эмне жана эмне үчүн ал аныкталбаган жүрүм-турум экенин түшүндүрүү;
  • жалпы абалды std::mutex жана RAII кайтаргычтары lock_guard менен unique_lock аркылуу коргоо;
  • агымдарды std::condition_variable аркылуу предикат менен күтүү идиомасын колдонуп координациялоо;
  • өз ара бөгөттөөнү (deadlock) таануу жана кулпулоо тартиби менен std::scoped_lock аркылуу андан качуу.

1. Конкуренттүүлүк жана параллелизм, жана std::thread

Конкуренттүүлүк - бул түзүлүш касиети: бир нече тапшырма кайчылашкан убакыт аралыгында иштеп жатат. Параллелизм - бул аткаруу касиети: тапшырмалар түз эле бир учурда ар башка ядролордо иштейт. Агымдар конкуренттүүлүктү туюнтууга мүмкүндүк берет; ал чыныгы параллелизмге айланабы - бул аппараттан көз каранды. Жеткиликтүү ядролордун санына кеңеш катары std::thread::hardware_concurrency() колдонуңуз.

std::thread (<thread>тен) өзүнүн чакырылуучу объектин конструкциялоодо дароо аткара баштайт. Сиз каалаган чакырылуучу объектти - функцияга көрсөткүчтү, лямбданы, функторду - плюс анын аргументтерин бересиз. Аргументтер демейде агымга көчүрүлөт; шилтеме менен берүү үчүн аларды std::refке ороп коюңуз.

#include <thread>
#include <iostream>

void greet(int id) { std::cout << "hello from " << id << "\n"; }

int main() {
    std::thread t(greet, 42);   // азыр иштей баштайт
    t.join();                   // бүткөнүн күтөбүз
}

std::thread жок кылынганга чейин анын тагдырын чечишиңиз керек: join() агым бүткөнгө чейин бөгөттөйт, ал эми detach() аны көз карандысыз иштеткенге коё берип, дескрипторуңузду үзөт. Эгер кошула турган (joinable) агымды экөөнүн бирин да жасабай жок кылсаңыз, деструктор std::terminate() чакырат жана программа үзгүлтүккө учурайт. Бул катаал эреже сиз кокусунан иштеп жаткан агымды жоготуп жибербеш үчүн бар.

C++20: std::jthread. jthread ("кошулуучу агым") бул тузакты оңдойт: анын деструктору автоматтык түрдө join жасайт, ошондуктан унутулган join мындан ары программаны токтотпойт. Ал ошондой эле std::stop_token алып жүрөт, ошентип агымдан кооперативдүү токтоону сураса болот. Жаңы C++20 кодунда std::jthreadти артык көрүңүз.

Бул сабакты YourAIZone платформасында улантыңыз

Толук сабакта — толук түшүндүрмө, чыгарылган мисалдар, көп кездешкен каталар, заматта текшерилүүчү тесттер жана ЖИ-репетитор. Конок катары дароо баштаңыз же прогрессти сактоо үчүн аккаунт түзүңүз.

Толук сабакта

  • Толук түшүндүрмө
  • Чыгарылган мисалдар
  • Көп кездешкен каталар жана алардан кантип качуу керек
  • Тест суроолору: 15
  • Тема боюнча суроолорго жооп берген ЖИ-репетитор
  • Окуучу, ата-эне жана мугалим үчүн прогрессти көзөмөлдөө