ফাউন্ডেশন
সরলীকৃত উদাহরণ দিয়ে শুরু করুন এবং প্রাসঙ্গিক বুস্টটি পরীক্ষা করুন Aএসিও টুকরা:
void handle_async_receive(...) { ... }
void print() { ... }
...
boost::asio::io_service io_service;
boost::asio::ip::tcp::socket socket(io_service);
...
io_service.post(&print);
socket.connect(endpoint);
socket.async_receive(buffer, &handle_async_receive);
io_service.post(&print);
io_service.run();
হ্যান্ডলার কী ?
একটি হ্যান্ডলার কলব্যাক ছাড়া আর কিছুই নয়। উদাহরণ কোডে 3 টি হ্যান্ডলার রয়েছে:
printহ্যান্ডলার (1)।
handle_async_receiveহ্যান্ডলার (3)।
printহ্যান্ডলার (4)।
একই print()ফাংশনটি দু'বার ব্যবহৃত হলেও প্রতিটি ব্যবহার তার নিজস্ব স্বতন্ত্র সনাক্তকরণযোগ্য হ্যান্ডলার তৈরি করতে বিবেচিত হয়। হ্যান্ডলারগুলি অনেকগুলি আকার এবং আকারে আসতে পারে, উপরের মতো মৌলিক ফাংশন থেকে শুরু করে আরও জটিল নির্মাণ যেমন ল্যাম্বডাস থেকে উত্পন্ন ফান্টেক্টর এবং আরও জটিল নির্মান থেকে শুরু করে boost::bind()। জটিলতা নির্বিশেষে, হ্যান্ডলার এখনও একটি কলব্যাক ছাড়া আর কিছুই অবশিষ্ট নেই।
কাজ কি ?
কাজটি এমন কিছু প্রক্রিয়াজাতকরণ যা বুস্ট.অ্যাসিওর কাছে আবেদন কোডের পক্ষে অনুরোধ করা হয়েছিল। কখনও কখনও বুস্ট.অ্যাসিও এটি সম্পর্কে কিছু বলা হওয়ার সাথে সাথে কিছু কাজ শুরু করতে পারে এবং অন্যান্য সময় এটি পরবর্তী সময়ে সময়ে কাজটি করার জন্য অপেক্ষা করতে পারে। কাজটি শেষ হয়ে গেলে, বুস্ট.এইসিও সরবরাহকৃত হ্যান্ডলারের সাহায্যে আবেদনটি জানিয়ে দেবে ।
Boost.Asio গ্যারান্টী বা নিশ্চয়তা হ্যান্ডেলার শুধুমাত্র একটি থ্রেড যে বর্তমানে কল করছে মধ্যে চালানো হবে run(), run_one(), poll(), অথবা poll_one()। এই থ্রেডগুলি যা কাজ করবে এবং কল করবে হ্যান্ডলারগুলি । অতএব, উপরের উদাহরণে, print()এটি io_service(1) এ পোস্ট করার সময় অনুরোধ করা হয় না । পরিবর্তে, এটিতে যুক্ত করা হয় io_serviceএবং পরবর্তী সময়ে একটি অনুরোধ করা হবে। এই ক্ষেত্রে এটি io_service.run()(5) এর মধ্যে রয়েছে।
অ্যাসিঙ্ক্রোনাস অপারেশনস কি?
একটি অ্যাসিঙ্ক্রোনাস অপারেশন কাজ তৈরি করে এবং বুস্ট.আসিয়াও কাজটি শেষ হয়ে গেলে অ্যাপ্লিকেশনটিকে জানাতে একটি হ্যান্ডলারকে অনুরোধ করবে । উপসর্গের সাথে একটি নাম রয়েছে এমন একটি ফাংশন কল করে অ্যাসিঙ্ক্রোনাস অপারেশন তৈরি করা হয় async_। এই ফাংশনগুলি সূচনা কার্য হিসাবেও পরিচিত ।
অ্যাসিনক্রোনাস অপারেশনগুলি তিনটি অনন্য পদক্ষেপে পচে যেতে পারে:
- সূচনা করা বা অবহিত করা, সম্পর্কিত
io_serviceযে কাজ করে তা করা দরকার। async_receiveঅপারেশন (3) জানায় io_serviceএটি সকেট থেকে অ্যাসিঙ্ক্রোনাস পড়া ডেটা করতে হবে, তারপর async_receiveঅবিলম্বে ফেরৎ।
- আসল কাজ করছেন। এই ক্ষেত্রে,
socketডেটা গ্রহণ করার সময়, বাইটগুলি পড়বে এবং এতে অনুলিপি হবে buffer। আসল কাজ দুটিতেই করা হবে:
- সূচনা ফাংশন (3), যদি বুস্ট.এসিও নির্ধারণ করতে পারে যে এটি ব্লক করবে না।
- যখন অ্যাপ্লিকেশন স্পষ্টভাবে চালিত
io_service(5)।
- Invoking
handle_async_receive ReadHandler । আবার, হ্যান্ডলারগুলি কেবল চালিত থ্রেডের মধ্যেই ডাকা হবে io_service। সুতরাং, কাজটি কখন (3 বা 5) হয় তা নির্বিশেষে, এটি গ্যারান্টিযুক্ত যে handle_async_receive()কেবলমাত্র io_service.run()(5) এর মধ্যেই ডাকা হবে ।
এই তিনটি ধাপের মধ্যে সময় এবং স্থানের বিভাজন নিয়ন্ত্রণ ফ্লো বিপরীত হিসাবে পরিচিত। এটি একটি জটিলতা যা অ্যাসিক্রোনাস প্রোগ্রামিংকে কঠিন করে তোলে। তবে এমন কিছু কৌশল রয়েছে যা এটিকে প্রশমিত করতে সহায়তা করতে পারে যেমন কর্টিন ব্যবহার করে ।
কি করে io_service.run()?
যখন কোনও থ্রেড কল করবে io_service.run(), তখন এই থ্রেডের মধ্যে থেকে কাজ এবং হ্যান্ডলারগুলি ডাকা হবে। উপরের উদাহরণে, io_service.run()(5) হয় অবধি ব্লক করবে:
- এটি উভয়
printহ্যান্ডলারের কাছ থেকে ফিরে এসেছে এবং ফিরে এসেছে , গ্রহণের ক্রিয়াটি সাফল্য বা ব্যর্থতার সাথে পরিপূর্ণ হয় এবং এর handle_async_receiveহ্যান্ডলারটি আহ্বান জানানো এবং ফিরে আসে।
io_serviceমাধ্যমে স্পষ্টভাবে বন্ধ থাকে io_service::stop()।
- হ্যান্ডলারের মধ্যে থেকে একটি ব্যতিক্রম ছুঁড়ে দেওয়া হয়।
একটি সম্ভাব্য psuedo-ish প্রবাহ নিম্নলিখিত হিসাবে বর্ণনা করা যেতে পারে:
io_service তৈরি করুন
সকেট তৈরি
io_service এ মুদ্রণ হ্যান্ডলার যুক্ত করুন (1)
সকেটের সংযোগের জন্য অপেক্ষা করুন (2)
io_service (3) এ একটি অ্যাসিঙ্ক্রোনাস পঠন কাজের অনুরোধ যুক্ত করুন
io_service এ মুদ্রণ হ্যান্ডলার যুক্ত করুন (4)
io_service চালান (5)
কাজ আছে নাকি হ্যান্ডলাররা?
হ্যাঁ, এখানে 1 টি কাজ এবং 2 জন হ্যান্ডলার রয়েছে
সকেটের কি ডেটা আছে? না, কিছু করবেন না
প্রিন্ট হ্যান্ডলার চালান (1)
কাজ আছে নাকি হ্যান্ডলাররা?
হ্যাঁ, এখানে 1 টি কাজ এবং 1 হ্যান্ডলার রয়েছে
সকেটের কি ডেটা আছে? না, কিছু করবেন না
প্রিন্ট হ্যান্ডলার চালান (4)
কাজ আছে নাকি হ্যান্ডলাররা?
হ্যাঁ, 1 টি কাজ আছে
সকেটের কি ডেটা আছে? না, অপেক্ষা অবিরত
- সকেট তথ্য গ্রহণ করে -
সকেটের ডেটা রয়েছে, এটি বাফারে পড়ুন
io_service- এ হ্যান্ডেল_সেনসি_র রিসিভ হ্যান্ডলার যুক্ত করুন
কাজ আছে নাকি হ্যান্ডলাররা?
হ্যাঁ, এখানে 1 জন হ্যান্ডলার রয়েছে
চালান হ্যান্ডেল_সায়েন্স_প্রাপ্ত হ্যান্ডলার (3)
কাজ আছে নাকি হ্যান্ডলাররা?
না, io_service সেট করে থামিয়ে দিয়ে ফিরে আসুন
পড়ার সমাপ্তিটি কীভাবে লক্ষ্য করুন, এটিতে অন্য একটি হ্যান্ডলার যুক্ত হয়েছে io_service। এই সূক্ষ্ম বিশদটি অ্যাসিক্রোনাস প্রোগ্রামিংয়ের একটি গুরুত্বপূর্ণ বৈশিষ্ট্য। এটি হ্যান্ডলারের একসাথে বেঁধে দেওয়া যায়। উদাহরণস্বরূপ, যদি handle_async_receiveএটি প্রত্যাশিত সমস্ত ডেটা না পেয়ে থাকে, তবে এর বাস্তবায়নটি আরও একটি অ্যাসিনক্রোনাস রিড অপারেশন পোস্ট করতে পারে যার ফলশ্রুতিতে io_serviceআরও বেশি কাজ রয়েছে এবং এভাবে ফিরে আসে না io_service.run()।
মনে রাখবেন যে যখন কি io_serviceকাজ পরিমাণ স্বল্প আছে, আবেদন অবশ্যই আবার চালানোর আগে।reset()io_service
উদাহরণ প্রশ্ন এবং উদাহরণ 3a কোড
এখন, প্রশ্নে উল্লেখ করা কোডের দুটি টুকরো পরীক্ষা করতে দিন।
প্রশ্ন কোড
socket->async_receiveকাজ যোগ করুন io_service। সুতরাং, io_service->run()পঠন অপারেশনটি সাফল্য বা ত্রুটির সাথে সম্পূর্ণ না হওয়া অবধি অবরুদ্ধ হবে এবং ClientReceiveEventএটি চলমান শেষ করে ফেলেছে বা একটি ব্যতিক্রম ছুঁড়েছে।
এটি বোঝা সহজ করার আশায়, এখানে একটি ছোট এনোটোটেড উদাহরণ 3 এ:
void CalculateFib(std::size_t n);
int main()
{
boost::asio::io_service io_service;
boost::optional<boost::asio::io_service::work> work =
boost::in_place(boost::ref(io_service));
boost::thread_group worker_threads;
for(int x = 0; x < 2; ++x)
{
worker_threads.create_thread(
boost::bind(&boost::asio::io_service::run, &io_service)
);
}
io_service.post(boost::bind(CalculateFib, 3));
io_service.post(boost::bind(CalculateFib, 4));
io_service.post(boost::bind(CalculateFib, 5));
work = boost::none;
worker_threads.join_all();
}
একটি উচ্চ-স্তরে, প্রোগ্রামটি 2 টি থ্রেড তৈরি করবে যা io_serviceইভেন্টটির লুপ (2) প্রসেস করবে । এটি একটি সাধারণ থ্রেড পুলের ফলস্বরূপ যা ফিবোনাচি সংখ্যা (3) গণনা করবে।
প্রশ্ন কোড এবং এই কোডের মধ্যে একটি প্রধান পার্থক্য হ'ল এই কোডটি প্রকৃত কাজ এবং হ্যান্ডলারের (3) এ যুক্ত হওয়ার আগেio_service::run() (2) ডাকে । অবিলম্বে প্রত্যাবর্তন থেকে রোধ করতে একটি বস্তু তৈরি করা হয় (1) এই অবজেক্টটি কাজ শেষ হতে বাধা দেয় ; অতএব, কোনও কাজের ফলে ফিরে আসবে না।io_serviceio_service::run()io_service::workio_serviceio_service::run()
সামগ্রিক প্রবাহ নিম্নরূপ:
io_service::workযুক্ত করা বস্তুটি তৈরি করুন এবং যুক্ত করুন io_service।
- থ্রেড পুল যে পূজা নির্মিত
io_service::run()। এই কর্মী থ্রেডগুলি বস্তুর io_serviceকারণে ফিরে আসবে না io_service::work।
- 3 টি হ্যান্ডলার যুক্ত করুন যা ফিবোনাচি নম্বরগুলিতে গণনা করে
io_serviceএবং তত্ক্ষণাত্ ফিরে আসে। শ্রমিকের থ্রেডগুলি, মূল থ্রেড নয়, এই হ্যান্ডলারগুলি অবিলম্বে চালানো শুরু করতে পারে।
io_service::workবস্তুটি মুছুন ।
- কর্মীদের থ্রেড চলমান শেষ হওয়ার জন্য অপেক্ষা করুন। এটি কেবলমাত্র 3 টি হ্যান্ডলারের মৃত্যুদন্ড কার্যকর করার পরে ঘটবে, কারণ
io_serviceউভয়টিরই হ্যান্ডলার বা কাজ নেই।
কোডটি অন্যভাবে লিখিত হতে পারে, মূল কোড হিসাবে একই পদ্ধতিতে, যেখানে হ্যান্ডলারগুলি যুক্ত করা হয় io_serviceএবং তারপরে io_serviceইভেন্ট লুপটি প্রক্রিয়া করা হয়। এটি ব্যবহারের প্রয়োজনীয়তা io_service::workএবং নিম্নলিখিত কোডে ফলাফলগুলি সরিয়ে দেয় :
int main()
{
boost::asio::io_service io_service;
io_service.post(boost::bind(CalculateFib, 3));
io_service.post(boost::bind(CalculateFib, 4));
io_service.post(boost::bind(CalculateFib, 5));
boost::thread_group worker_threads;
for(int x = 0; x < 2; ++x)
{
worker_threads.create_thread(
boost::bind(&boost::asio::io_service::run, &io_service)
);
}
worker_threads.join_all();
}
সিঙ্ক্রোনাস বনাম অ্যাসিনক্রোনাস
যদিও প্রশ্নের কোডটি একটি অ্যাসিনক্রোনাস অপারেশন ব্যবহার করছে, এটি কার্যকরভাবে সিঙ্ক্রোনাসের সাথে কাজ করছে, কারণ এটি অ্যাসিনক্রোনাস অপারেশনটি সম্পন্ন হওয়ার জন্য অপেক্ষা করছে:
socket.async_receive(buffer, handler)
io_service.run();
সমান:
boost::asio::error_code error;
std::size_t bytes_transferred = socket.receive(buffer, 0, error);
handler(error, bytes_transferred);
থাম্বের একটি সাধারণ নিয়ম হিসাবে, সিঙ্ক্রোনাস এবং অ্যাসিনক্রোনাস অপারেশনগুলি মিশ্রণ এড়াতে চেষ্টা করুন। প্রায়শই, এটি একটি জটিল ব্যবস্থাকে একটি জটিল ব্যবস্থায় পরিণত করতে পারে। এই উত্তরটি অ্যাসিক্রোনাস প্রোগ্রামিংয়ের সুবিধাগুলি তুলে ধরেছে যার কয়েকটি বুস্ট.অ্যাসিও ডকুমেন্টেশনেও রয়েছে ।