লুপ মুদ্রণের ভুল মানগুলির জন্য সি ++ ভিতরে থ্রেড


19

আমি সি ++ এ মাল্টি-থ্রেডিং বোঝার চেষ্টা করছি, তবে আমি এই সমস্যায় আটকে আছি: আমি যদি লুপের জন্য থ্রেড চালু করি তবে তারা ভুল মানগুলি মুদ্রণ করে। এই কোড:

#include <iostream>
#include <list>
#include <thread>

void print_id(int id){
    printf("Hello from thread %d\n", id);
}

int main() {
    int n=5;
    std::list<std::thread> threads={};
    for(int i=0; i<n; i++ ){
        threads.emplace_back(std::thread([&](){ print_id(i); }));
    }
    for(auto& t: threads){
        t.join();
    }
    return 0;
}

আমি 0,1,2,3,4 মানগুলি মুদ্রিত হওয়ার প্রত্যাশা করছিলাম তবে আমি প্রায়শই একই মান দুটি বার পেয়েছি। এটি আউটপুট:

Hello from thread 2
Hello from thread 3
Hello from thread 3
Hello from thread 4
Hello from thread 5

আমি কী মিস করছি?


7
ল্যাম্বদা iমান দ্বারা পাস [i],।
rafix07

1
এটা তোলে এর মূল্য লক্ষ করেন, আপনার ব্যবহার emplace_backবিজোড়: emplace_backআর্গুমেন্ট এর একটি তালিকায় নেয় এবং একটি কন্সট্রাকটর উপর যে পাসের std::thread। আপনি একটি (মূল্য) উদাহরণ পাস করেছেন std::thread, অতএব একটি থ্রেড তৈরি করবেন, তারপরে সেই থ্রেডটিকে ভেক্টরে স্থানান্তরিত করুন। এই অপারেশনটি আরও সাধারণ পদ্ধতি দ্বারা আরও ভালভাবে প্রকাশ করা হয় push_back। এটি আরও বোধগম্য হয় লিখতে threads.emplace_back([i](){ print_id(i); });(স্থানে নির্মাণ করা) বা threads.push_back(std::thread([i](){ print_id(i); }));(কনস্ট্রাক্ট + মুভ) আরও বেশি বুদ্ধিমান হতে চাই ।
মিলো ব্র্যান্ড্ট

উত্তর:


17

[&]সিনট্যাক্স হয় যার ফলে iবন্দী করা রেফারেন্স দ্বারাiথ্রেডটি আপনি প্রত্যাশার চেয়ে চালিত হলে প্রায়শই প্রায়শই আরও অগ্রসর হন। আরও গুরুতরভাবে, কোনও থ্রেড চলার আগে যদি সুযোগের বাইরে চলে যায় তবে আপনার কোডের আচরণটি সংজ্ঞায়িতi

iমান অনুসারে ক্যাপচারিং - std::thread([i](){ print_id(i); })এটি ঠিক করা।


2
বা কম ব্যবহৃত হয় এবং প্রায়শই পরামর্শ দেওয়া যায় নাstd::thread([=](){ print_id(i); })
ওয়ান্ডার

3
আচরণটি ইতিমধ্যে সংজ্ঞায়িত হয়েছে কারণ iএটি মূল থ্রেড রচনা এবং অন্যান্য থ্রেড রিডিং সহ (অ-পারমাণবিক) একটি ডেটা রেস ।
আখরোট

6

দুটি সমস্যা:

  1. থ্রেড চলার সময় আপনার কোনও নিয়ন্ত্রণ নেই, যার অর্থ iল্যাম্বডায় ভেরিয়েবলের মান আপনার প্রত্যাশা মতো নাও হতে পারে।

  2. চলকটি কেবল iলুপ এবং লুপের জন্য স্থানীয়। যদি এক বা একাধিক থ্রেড চলার আগে লুপটি শেষ হয়, তবে সেই থ্রেডগুলির একটি চলকটির একটি অবৈধ রেফারেন্স থাকবে যার জীবনকাল শেষ হয়েছে।

আপনি পরিবর্তনশীল ক্যাপচার দ্বারা খুব সহজভাবে উভয় এই সমস্যার সমাধান করতে পারে i মান পরিবর্তে রেফারেন্স দ্বারা। তার মানে প্রতিটি থ্রেডের মানটির একটি অনুলিপি থাকবে এবং সেই অনুলিপি প্রতিটি থ্রেডের জন্য স্বতন্ত্রভাবে তৈরি করা হবে।


5

আরেকটি জিনিস:
সর্বদা অর্ডারযুক্ত ক্রম না হওয়া পর্যন্ত অপেক্ষা করবেন না: 0, 1, 2, 3, ... কারণ বহুগঠিত সম্পাদন মোডের একটি নির্দিষ্টতা রয়েছে: অনির্দিষ্টকালের জন্য

নির্বিচারতা মানে একই কর্মসূচি একই পরিস্থিতিতে কার্যকর করা অন্যরকম ফলাফল দেয়।

এটি বেশিরভাগ পরামিতিগুলির উপর নির্ভর করে ওএসের শিড্যুল্যগুলি একটি কার্যকরকরণ থেকে অন্যটিতে পৃথকভাবে থ্রেড করে তোলে: সিপিইউ লোড, অন্যান্য প্রক্রিয়াগুলির অগ্রাধিকার, সম্ভাব্য সিস্টেমের বাধা, ...

আপনার উদাহরণে কেবল 5 টি থ্রেড রয়েছে, সুতরাং এটি সহজ, থ্রেডের সংখ্যা বাড়ানোর চেষ্টা করুন এবং উদাহরণস্বরূপ প্রক্রিয়াকরণ কার্যটিতে একটি ঘুম দিন, আপনি দেখতে পাবেন যে ফলাফলটি এক মৃত্যুদন্ড থেকে অপরটিতে কার্যকর হতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.