Std :: থ্রেড এখনও চলছে কিনা তা কীভাবে পরীক্ষা করবেন?


86

কোনও std::threadএখনও চলছে (প্ল্যাটফর্মটি স্বাধীনভাবে) চলছে কিনা তা আমি কীভাবে পরীক্ষা করতে পারি ? এটিতে কোনও timed_join()পদ্ধতির অভাব রয়েছে এবং joinable()এটি এর জন্য নয়।

আমি std::lock_guardথ্রেডের সাথে একটি মুটেক্সকে লক করার এবং try_lock()মুটেক্সের পদ্ধতিটি এখনও এটি লকড আছে কিনা তা নির্ধারণ করার জন্য (থ্রেডটি চলমান) ব্যবহার করার কথা ভেবেছিলাম তবে এটি আমার কাছে অকারণে জটিল বলে মনে হচ্ছে।

আপনি কি আরও মার্জিত পদ্ধতি জানেন?

আপডেট: পরিষ্কার হতে: আমি থ্রেডটি পরিষ্কারভাবে বেরিয়েছে কিনা তা পরীক্ষা করে দেখতে চাই। একটি 'ঝুলন্ত' থ্রেড এই উদ্দেশ্যে চলমান হিসাবে বিবেচিত হয়।


আমি অনুমান করি যে কোনও থ্রেড এখনও চলছে কেবলমাত্র তখনই wait()এটির জন্য প্রত্যাশা করা হয় এবং যদি তাই হয়, আপনি যদি wait()এখনও এটির জন্য সম্পাদনা না করে থাকেন তবে তাকে অবশ্যই সংজ্ঞা অনুসারে চলতে হবে। তবে এই যুক্তিটি নিখুঁত হতে পারে।
আগে

আসলে আমার কাছে একটি থ্রেড রয়েছে যা ব্যতিক্রমী শর্তের বাইরে চলে যায় এবং আমি মূল থ্রেডটি এখনও চলমান থাকলে তা যাচাই করতে চাই, তবে এটির জন্য অপেক্ষা করতে চাই না (যোগ দিতে)
kispaljr

4
দৌড় দিয়ে আসলে কী বুঝ? আপনি কী বোঝাতে চেয়েছেন এটি অপেক্ষার রাজ্যের চেয়ে সক্রিয়ভাবে প্রক্রিয়াজাতকরণ করছে, বা আপনি কী বোঝাচ্ছেন যে থ্রেডটি এখনও বিদ্যমান আছে এবং শেষ হয়নি?
ক্যাশকো

আপনি সর্বদা বুস্ট ব্যবহার করতে পারেন :)
ক্যাশকো

4
আপনি যদি সন্তুষ্ট না হন তবে আপনার কোনও উত্তর গ্রহণ করা উচিত নয়।
নিকোল বোলাস

উত্তর:


120

আপনি যদি সি ++ 11 ব্যবহার করতে std::asyncএবং std::futureআপনার কাজগুলি চালাতে ইচ্ছুক হন তবে থ্রেডটি এখনও এইভাবে পরিষ্কারভাবে চলছে কিনা তা যাচাই করার wait_forজন্য std::futureআপনি এই কার্যটি ব্যবহার করতে পারেন :

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    /* Run some task on new thread. The launch policy std::launch::async
       makes sure that the task is run asynchronously on a new thread. */
    auto future = std::async(std::launch::async, [] {
        std::this_thread::sleep_for(3s);
        return 8;
    });

    // Use wait_for() with zero milliseconds to check thread status.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    auto result = future.get(); // Get result.
}

আপনার যদি অবশ্যই ব্যবহার করতে হয় std::threadতবে আপনি std::promiseভবিষ্যতের কোনও জিনিস পেতে ব্যবহার করতে পারেন :

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    // Create a promise and get its future.
    std::promise<bool> p;
    auto future = p.get_future();

    // Run some task on a new thread.
    std::thread t([&p] {
        std::this_thread::sleep_for(3s);
        p.set_value(true); // Is done atomically.
    });

    // Get thread status using wait_for as before.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    t.join(); // Join thread.
}

এই উদাহরণ দুটিই আউটপুট হবে:

Thread still running

এটি অবশ্যই কারণ টাস্ক শেষ হওয়ার আগে থ্রেডের স্থিতি পরীক্ষা করা হয়।

তবে আবার, অন্যদের ইতিমধ্যে উল্লিখিত মতো এটি করা সহজ হতে পারে:

#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    std::atomic<bool> done(false); // Use an atomic flag.

    /* Run some task on a new thread.
       Make sure to set the done flag to true when finished. */
    std::thread t([&done] {
        std::this_thread::sleep_for(3s);
        done = true;
    });

    // Print status.
    if (done) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    t.join(); // Join thread.
}

সম্পাদনা করুন:

এর রয়েছে std::packaged_taskসাথে ব্যবহারের জন্য std::threadব্যবহার না করে একটি ক্লিনার সমাধান জন্য std::promise:

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    // Create a packaged_task using some task and get its future.
    std::packaged_task<void()> task([] {
        std::this_thread::sleep_for(3s);
    });
    auto future = task.get_future();

    // Run task on new thread.
    std::thread t(std::move(task));

    // Get thread status using wait_for as before.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        // ...
    }

    t.join(); // Join thread.
}

4
চমৎকার উত্তর. আমি যুক্ত করব যে এটি কোনও রিটার্ন মান এবং ভবিষ্যত ছাড়াই থ্রেডগুলির সাথেও কাজ করে <void>
kispaljr

এই কোডের কারণ কী std::atomic<bool> done(false);? boolপরমাণু কি ডিফল্ট নয়?
হাই-অ্যাঞ্জেল '

6
@ ইয়াগামাইলাইট ইন সি ++ এটিকে আবদ্ধ না করা ছাড়া ডিফল্টরূপে কিছুই পারমাণবিক নয় std::atomicsizeof(bool)বাস্তবায়ন সংজ্ঞায়িত হয় এবং এটি 1> হতে পারে, সুতরাং এটি সম্ভব যে কোনও আংশিক লেখার ঘটনা ঘটতে পারে। ক্যাশে
একত্রিত হওয়ার বিষয়টিও আছে

4
@ ইয়াগামাইটলাইট এখানে আরও তথ্য: কখন আমার সত্যিকার অর্থে
স্ন্যাপস

4
নোট করুন যে স্ট্যান্ড :: ক্রোনো_লাইট্রালগুলি সংকলনের জন্য সি ++ 14 লাগবে
প্যাট্রিজিও

5

একটি সহজ সমাধান হ'ল নিয়মিত বিরতিতে থ্রেডটি সত্য হয়ে যায় এবং এটি পরীক্ষা করে স্ট্যাটাসটি জানতে চাইলে থ্রেড দ্বারা মিথ্যাতে সেট করা হয়। পরিবর্তনশীল যদি দীর্ঘ সময়ের জন্য মিথ্যা থাকে তবে থ্রেডটি আর সক্রিয় বিবেচিত হবে না।

আরও একটি থ্রেড-নিরাপদ উপায় হ'ল একটি পাল্টা যা শিশু থ্রেড দ্বারা বৃদ্ধি পায় এবং মূল থ্রেডটি কাউন্টারটিকে একটি সঞ্চিত মানের সাথে তুলনা করে এবং যদি দীর্ঘ সময় পরে একই হয় তবে শিশু থ্রেডটি সক্রিয় নয় বলে বিবেচিত হয়।

তবে খেয়াল করুন, সি ++ 11 এ আসলে ঝুলানো থ্রেডটি হত্যা বা সরানোর কোনও উপায় নেই।

সম্পাদনা করুন কীভাবে কোনও থ্রেড পরিষ্কারভাবে বেরিয়ে এসেছে কিনা তা পরীক্ষা করে দেখুন: মূলত প্রথম অনুচ্ছেদে বর্ণিত একই কৌশল; বুলিয়ান ভেরিয়েবলটি মিথ্যা থেকে শুরু করে দিন। সন্তানের থ্রেডটি শেষ কাজটি সত্যে সেট করে। তারপরে মূল থ্রেডটি সেই পরিবর্তনশীলটি যাচাই করতে পারে, এবং সত্য (সত্য) যদি কোনও বাধা ছাড়াই শিশু থ্রেডে যোগ দেয়।

Edit2 একটি ব্যতিক্রম কারণে থ্রেড প্রস্থান করে, তারপর দুই থ্রেড "মেন" ফাংশন থাকে: প্রথম এক একটি আছে try- catchভিতরে যা দ্বিতীয় "বাস্তব" মূল থ্রেড ফাংশন কল। এই প্রথম প্রধান ফাংশনটি "have_exited" ভেরিয়েবল সেট করে। এটার মতো কিছু:

bool thread_done = false;

void *thread_function(void *arg)
{
    void *res = nullptr;

    try
    {
        res = real_thread_function(arg);
    }
    catch (...)
    {
    }

    thread_done = true;

    return res;
}

4
যদি ওপরের সংজ্ঞাটি হয় "চলমান"।
ক্যাশকো

আপনি আমাকে ভুল বুঝতে পারে। আমি কোনও থ্রেড পরিষ্কারভাবে বেরিয়েছে কিনা তা পরীক্ষা করে দেখতে চাই। অস্পষ্ট কথার জন্য দুঃখিত।
কিসপালজর

7
যদি বিভিন্ন থ্রেড পড়তে এবং লিখতে থাকে thread_doneতবে এই কোডটি কোনও মেমরির বাধা ছাড়াই ভেঙে যায়। std::atomic<bool>পরিবর্তে ব্যবহার করুন।
iljarn

4
আমি একাধিক কর্মী থ্রেডের কথা উল্লেখ করছিলাম না, আমি boolমূল এক থ্রেডটি পড়ার সময় একক কর্মী থ্রেড লেখার কথা উল্লেখ করছিলাম - এর জন্য একটি স্মৃতি বাধা দরকার।
iljarn

4
কেন এখানে প্রয়োজনীয় তা নিয়ে আলোচনার জন্য এই প্রশ্নটি দেখুন std::atomic<bool>
রবার্ট রাজার

2

এই সহজ পদ্ধতিটি আপনি জোড় পদ্ধতিতে অবরুদ্ধ না করে কোনও থ্রেড সমাপ্তি সনাক্তকরণের জন্য ব্যবহার করতে পারেন।

std::thread thread([&thread]() {
    sleep(3);
    thread.detach();
});

while(thread.joinable())
    sleep(1);

4
থ্রেডটিকে বিচ্ছিন্ন করা শেষ পর্যন্ত কোনওটি যা চায় তা নয় এবং যদি আপনি এটি না করেন তবে আপনাকে এমন join()কিছু থ্রেড থেকে কল করতে হবে যা থ্রেডটির joinable()সম্পত্তি হ্রাস করার জন্য অপেক্ষা করে না , অন্যথায় এটি নিরবচ্ছিন্নভাবে লুপ হয়ে যাবে (অর্থাত joinable()থ্রেডটি সত্য না হওয়া পর্যন্ত সত্য ফিরে আসে) join()এডি এবং শেষ না হওয়া পর্যন্ত)
নিক্লাস আর

যোগদানযোগ্য মানে একটি থ্রেড থ্রেড হ্যান্ডেলটি ধারণ করে। থ্রেডটি করা হয়ে গেলে এটি এখনও যুক্ত হতে পারে। আপনার যদি থ্রেডটির শেষের অপেক্ষায় না থেকে পরীক্ষা করতে হয় তবে সমাধানটি এখানে। এটি কোডের কয়েকটি লাইন। আপনি কেন প্রথমে চেষ্টা করলেন না?
এভজেনি কার্পভ

আমি করেছি, এবং আমি যে বিষয়টিটি তৈরির চেষ্টা করছি তা হ'ল আপনি যদি thread.detach()অংশটি সরিয়ে দেন তবে উপরের প্রোগ্রামটি কখনই শেষ হবে না।
নিক্লাস আর

হ্যাঁ, এটা হবে না। এ কারণেই এটি শেষের দিকে বিচ্ছিন্নতা বলে।
এভজেনি কার্পভ

4
মিউটেক্স এবং আরও জটিল সমাধানের প্রয়োজনীয়তার সাথে বিযুক্তকরণ বিলোপের কল করার এই পদ্ধতি। আমি এটি ব্যবহার করি এবং এটি কাজ করে! উত্তর করার জন্য ধন্যবাদ.
সেপ্টেম্বর

1

চলমান থ্রেড এবং কলিং থ্রেড উভয়েরই অ্যাক্সেস রয়েছে এমন একটি মিউটেক্স তৈরি করুন। চলমান থ্রেডটি যখন শুরু হয় তখন এটি মিটেক্সটিকে লক করে রাখে এবং এটি শেষ হলে এটি মিটেক্সটি আনলক করে। থ্রেডটি এখনও চলছে কিনা তা পরীক্ষা করার জন্য, কলিং থ্রেডটি mutex.try_lock () কে কল করে। এর রিটার্ন মান হ'ল থ্রেডের স্থিতি। (চেষ্টা_লক যদি কাজ করে তবেই কেবল মিটেক্সটি আনলক করার বিষয়টি নিশ্চিত করুন)

এটির সাথে একটি ছোট সমস্যা, থ্রেডটি তৈরি হওয়ার সময় এবং এটি যখন মিউটেক্সটিকে লক করে রাখে তার মাঝে মিটেক্স.ট্রি_লক () মিথ্যা প্রত্যাবর্তন করে তবে এটি আরও জটিল পদ্ধতি ব্যবহার করে এড়ানো যায়।


-1 আপনার std::mutexএই ধরণের সিগন্যালিংয়ের জন্য ব্যবহার করা উচিত নয় (বেশিরভাগ ক্ষেত্রে কীভাবে মুটেেক্স সাধারণত প্রয়োগ করা হয় তার কারণেই)। একটি atomic_flagউপায় যেমন কম ওভারহেড সঙ্গে ঠিক এই ক্ষেত্রে কাজ করে। একটি std::futureআরও ভাল হতে পারে কারণ এটি অভিপ্রায়টি আরও স্পষ্টভাবে প্রকাশ করে। এছাড়াও, মনে রাখবেন যে try_lockউদ্দীপনার সাথে ব্যর্থ হতে পারে, সুতরাং প্রত্যাবর্তনটি অবশ্যই থ্রেডের স্থিতি নয় (যদিও এটি সম্ভবত এই বিশেষ ক্ষেত্রে আপনাকে খুব বেশি ক্ষতি করবে না)।
কমিকসান্সএসএমএস

1

আপনি সর্বদা থ্রেডের আইডি স্ট্যান্ড :: থ্রেড :: আইডি () ডিফল্ট তৈরির চেয়ে আলাদা কিনা তা পরীক্ষা করতে পারেন। একটি চলমান থ্রেডে সর্বদা একটি আসল সম্পর্কিত আইডি থাকে। অত্যধিক অভিনব জিনিস এড়ানোর চেষ্টা করুন :)


0

অবশ্যই একটি মুটেক্স-মোড়কযুক্ত ভেরিয়েবলের আরম্ভ করা আছে false, থ্রেডটি trueপ্রস্থান করার আগে এটি শেষ জিনিস হিসাবে সেট করে। এটি কি আপনার প্রয়োজনের জন্য যথেষ্ট পারমাণবিক?


4
আপনি যদি যাইহোক কোনও মিটেক্স ব্যবহার করেন তবে আমি আমার সমাধানটি অনুভব করি (কেবলমাত্র মুটেক্স, ডাব্লু / ও বুলিয়ান ব্যবহার করে) আরও মার্জিত হতে। আপনি যদি পুরোপুরি কোনও থ্রেড-সেফ বুলেট ব্যবহার করতে চান তবে আমি পরিবর্তে std :: পরমাণু <বিউল> এর সুপারিশ করব। বেশিরভাগ বাস্তবায়নে এটি লক-ফ্রি হবে।
কিসপালজর

কেন একেবারে লক? একটি থ্রেড কেবল কখনও পড়েন, একটি কেবল কখনও লেখেন। এবং শব্দের আকারের লেখাগুলি যে কোনও ক্ষেত্রেই পারমাণবিক IR
Xeo

4
@ শিও: লিখনটি পারমাণবিক হতে পারে তবে আপনি যদি অন্য থ্রেডের লিখিত মানটি দেখতে প্রত্যাশা করেন (তবে এটি কোনও আলাদা সিপিইউতে কার্যকর হতে পারে) তবে মেমোরি বাধা প্রয়োজন। std::atomic<bool>আপনার জন্য এটি যত্ন করে, তাই এটি আসল উত্তর আইএমও।
iljarn
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.