הקדמה לC++ לא היה סטנדרט לתהליכונים או אסינכרוניות עד לגרסה 11.
בC++ 11 יצאו מגוון רחב של האדרים שאפשרו לבצע קוד מקבילי ואסינכרוני.future וב-std::async(...).  
נראה איך בקלות נוכל להריץ קוד אסינכורני ולחכות לתוצאה שלו!  
ובסוף נקשר את זה לתצורה חדשה של co routine שנוספו ב-C++ 20.
include Future future מוסיף יכולות אסינכרוניות ומאפשר להריץ קוד, לחכות לתשובה או לשגיאה.  
הדרך הכי פשוטה להריץ קוד אסינכרוני הוא בעזרת std::async:  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include  <future>  #include  <iostream>  #include  <chrono>  int  main () 	using  namespace  std::chrono_literals; 	auto  printHi = []() 	{ 		std::this_thread::sleep_for (500 ms); 		auto  tId = std::this_thread::get_id (); 		std::cout << "Hello from "  << tId << "\n" ; 	}; 	printHi (); 	auto  fut = std::async (std::launch::async, printHi); 	return  0 ; } 
להרצה הזו יש 2 אופציות:  
async - מריץ את הקוד אסינכרוני.   
deferred - מריץ את הקוד בצורה עצלנית - בפעם הראשונה שמישהו ייבקש את התוצאה. 
 
1 auto  fut = std::async (std::launch::async, printHi);
async מחזיר אובייקט future שעליו ניתן לחכות.future.wait(), או לחכות שהוא שייעבור destructor והתוצאה תבוקש.  
אם נרצה להריץ את הקוד מאוחר יותר בצורה עצלנית נוכל לקרוא ישירות ל-get:  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include  <future>  #include  <iostream>  #include  <chrono>  int  main () 	using  namespace  std::chrono_literals; 	auto  printHi = []() 	{ 		auto  tId = std::this_thread::get_id (); 		std::cout << "Hello from "  << tId << "\n" ; 	}; 	printHi (); 	auto  fut = std::async (std::launch::deferred, printHi); 	std::cout << "Waiting 2 seconds...\n" ; 	std::this_thread::sleep_for (2 s); 	std::cout << "Calling for deferred\n" ; 	fut.get (); 	return  0 ; } 
מה שהודפס:  
1 2 3 4 Hello from 3600 Waiting 2 seconds... Calling for deferred Hello from 3600 
שימו לב שזה רץ על אותו תהליכון הפעם :)  
Promise אובייקט ה-promise מאחסן ערך עבור פעולה אסינכרונית.  
בדוגמא פה אנחנו מבצעים חישוב אסינכרוני ושומרים את הערך ב-promise.future ולא - promise אנחנו יכולים לשלוט על התוצאה האסינכרונית.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include  <future>  #include  <iostream>  #include  <chrono>  using  namespace  std::chrono_literals;using  MyHash = unsigned  long  long ;struct  HasherWaiter { 	std::future<MyHash> operator () (std::string name)   	 {		mHashingFuture = std::async (std::launch::async, [&]() 			{ 				std::this_thread::sleep_for (5 s); 				std::hash<std::string> h; 				auto  hash = (MyHash)h (name); 				mPromise.set_value (hash); 			}); 		return  mPromise.get_future (); 	} private :	std::future<void > mHashingFuture; 	std::promise<MyHash> mPromise; }; int  main () 	HasherWaiter hahser; 	auto  future = hahser ("Hello World" ); 	while  (!future._Is_ready()) 	{ 		std::this_thread::sleep_for (500 ms); 		std::cout << "Waiting for hash...\n" ; 	} 	std::cout << "Hash is "  << future.get () << "\n" ; 	return  0 ; } 
packaged_task האובייקט packaged_task אורז פונקציה או פעולה אחרת מכל סוג שהוא לכדי פעולה אסינכרונית.future שנוכל להשתמש בו כדי לחזור לתוצאה האסינכרונית.  
בדוגמא הזו מתבצע חישוב מפונקציה אחרת,bind הפונקציה מוחדרת לכל ה-packaged_task.API של לינוקס או ווינדוס.API חיצוני שאין לנו דרך לשנות אותו, אנחנו יכולים ככה לעטוף אותו ולהוסיף אסינכרוניות לקוד שלנו.  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include  <future>  #include  <iostream>  #include  <chrono>  int  RectangleArea (int  width, int  height)  return  width * height; }struct  Calculator { 	Calculator () : mTask (std::bind (RectangleArea, 55 , 22 )) { } 	std::future<int > CalculateArea ()   	 {		mTask (); 		return  mTask.get_future (); 	} private :	std::packaged_task<int ()> mTask; }; int  main () 	Calculator calc; 	auto  result = calc.CalculateArea (); 	std::cout << "Area: "  << result.get () << "\n" ; 	return  0 ; } 
std::async כל כך קל ונוח לשימוש.
C++ 20 מוסיפה יכולות חדשות שנקראות - co routine.  
Co routine הדגמה אני לא אסביר יותר מדי, אך נעבור על קוד לראות איך זה נראה.  
MSVC תבנו על C++ הגרסא הכי חדשה./await לקומפיילר.  
GCC g++ -fcoroutines -std=c++20
CLANG clang++ -std=c++20 -stdlib=libc++ -fcoroutines-ts
Genertor ג’נרטור כמו בפייתון הוא אובייקט המאפשר בצורה עצלנית ליצור ערכים:  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include  <iostream>  #include  <experimental/coroutine>  #include  <experimental/generator>  #include  <coroutine>  std::experimental::generator<int > WalkTo (int  n)  noexcept   	auto  i = 0 ; 	while  (i < n) 	{ 		co_yield  i; 		i++; 	} } int  main () 	auto  g = WalkTo (5 ); 	auto  itr = g.begin (); 	std::cout << *itr << "\n" ; 	itr++; 	std::cout << *itr << "\n" ; 	itr++; 	std::cout << *itr << "\n" ; 	itr++; 	return  0 ; } 
co_await זה הולך להיות קוד מעניין.MSVC.  
ממליץ לקרוא פה:https://devblogs.microsoft.com/cppblog/ 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 #include  <iostream>  #include  <chrono>  #include  <future>  #include  <windows.h>      using  namespace  std;using  namespace  std::literals;auto  operator  co_await (chrono::system_clock::duration duration) 	using  namespace  std::experimental; 	 	 	 	 	class  awaiter  	{ 		static  			void  CALLBACK TimerCallback (PTP_CALLBACK_INSTANCE,  				void * Context, 				PTP_TIMER) 		 {			 			coroutine_handle<>::from_address (Context).resume (); 		} 		PTP_TIMER timer = nullptr ; 		chrono::system_clock::duration duration; 	public : 		explicit  			awaiter (chrono::system_clock::duration d)  : duration(d) 		{ }		~awaiter () { 			if  (timer) CloseThreadpoolTimer (timer); 		} 		 		 		bool  await_ready ()  const  		 {			return  duration.count () <= 0 ; 		} 		 		bool  await_suspend (coroutine_handle<> resume_cb)  		 {			int64_t  relative_count = -duration.count (); 			timer = CreateThreadpoolTimer (TimerCallback, 				resume_cb.address (), 				nullptr ); 			 			SetThreadpoolTimer (timer, (PFILETIME)&relative_count, 0 , 0 ); 			return  timer != 0 ; 		} 		 		 		void  await_resume ()   	}; 	return  awaiter{ duration }; } future<void > test ()  	cout << this_thread::get_id () << ": sleeping…\n" ; 	 	co_await  5000 ms; 	cout << this_thread::get_id () << ": woke up\n" ; } void  usecase () 	test ().get (); 	cout << this_thread::get_id () << ": back in main\n" ; } int  main () 	usecase (); 	return  0 ; } 
לפונקציית קו-רוטינה צריכה להיות 4 פעולות:  
מה ששונה בין קו-רוטינה לסאב-רוטינה זה שלסאב-רוטינה אין יכולה להפעיל ולהשעות את עצמה.  
co_await דורשת 3 פונקציות בתור הממשק שלה:  
await_ready 
await_suspend 
await_resume 
 
future מקיים את זה בעזרת _Future_awaiter, ולכן נוכל לעשות אדפטציה כזו בין future ל-awaiter.  
ב-C++11:std::async ו -future נותנים לנו אדפטציה קלה לפונקציות אסינכרוניות.  
עכשיו ב-C++ 20 העלנו שלב ומשלבים את כל הקונספטים לכדי הרצה פשוטה יותר וגנרית יותר של קוד אסינכרוני ומקבילי.  
במה זה ייעזור לנו?  
לבנות שרתי רשת יותר יעילים.   
לבנות משחקים יותר טובים.   
אלגוריתמיקה יותר מהירה 
AI פשוט יותר 
 
לקריאה מעמיקה יותר בנושא הקו-רוטינות:  
https://luncliff.github.io/coroutine/articles/exploring-msvc-coroutine/#awaitable-interface 
https://en.cppreference.com/w/cpp/language/coroutines 
https://www.scs.stanford.edu/~dm/blog/c++-coroutines.html 
תודה על הקריאה!