এই কোডটি রিলিজ মোডে ঝুলছে তবে ডিবাগ মোডে সূক্ষ্মভাবে কাজ করে


110

আমি এটি পেরিয়ে এসেছি এবং ডিবাগ এবং রিলিজ মোডে এই আচরণের কারণ জানতে চাই।

public static void Main(string[] args)
{            
   bool isComplete = false;

   var t = new Thread(() =>
   {
       int i = 0;

        while (!isComplete) i += 0;
   });

   t.Start();

   Thread.Sleep(500);
   isComplete = true;
   t.Join();
   Console.WriteLine("complete!");
}

25
আচরণের মধ্যে পার্থক্য কী?
— মং ঝু

4
এটি জাভা থাকলে আমি ধরে নিই যে সংকলকটি 'সংকলন' পরিবর্তনশীলটির আপডেট দেখতে পাচ্ছে না। পরিবর্তনশীল ঘোষণায় 'অস্থির' যুক্ত করা ঠিক করে দেয় (এবং এটি একটি স্ট্যাটিক ক্ষেত্র তৈরি করে)।
— সেবাস্তিয়ান


4
দ্রষ্টব্য: এই কারণেই মাল্টিথ্রেডেড ডিভলপমেন্টে মিটেক্সেস এবং পারমাণবিক ক্রিয়াকলাপের মতো জিনিস রয়েছে। আপনি যখন মাল্টিথ্রেড করা শুরু করবেন, আপনাকে অতিরিক্ত মেমরি সমস্যাগুলির একটি উল্লেখযোগ্য সেট বিবেচনা করতে হবে যা আগে স্পষ্ট ছিল না। মুডেক্সেসের মতো থ্রেডিং সিঙ্ক্রোনাইজেশন সরঞ্জামগুলি এর সমাধান করত।
— কর্ট

5
@ ডেভিডশওয়ার্টজ: অবশ্যই অনুমোদিত । এবং এটা করা হয় অনুমতি কম্পাইলার, রানটাইম এবং CPU- র যে কোড ফল কি আপনি আশা করতে আলাদা হতে কাজকে আপনার জন্য। বিশেষত, সি # তে বুল অ্যাক্সেসকে অ্যানোট্যাটিক করার অনুমতি দেওয়া হয় না , তবে এটি অ-অস্থির পড়াকে সময়মতো পিছনে সরিয়ে আনার অনুমতি দেওয়া হয়। দ্বিগুণ, বিপরীতে, পারমাণবিকতার উপর এই জাতীয় কোনও বিধিনিষেধ নেই; সিঙ্ক্রোনাইজেশন ছাড়াই দুটি ভিন্ন থ্রেডে একটি ডাবল পঠিত এবং লিখিত ছিঁড়ে যাওয়ার অনুমতি রয়েছে।
— এরিক লিপার্ট

উত্তর:


149

আমি অনুমান করি যে চলকটিতে 'উদ্বায়ী' কীওয়ার্ডের অভাবের কারণে অপ্টিমাইজারটি বোকা হয়ে যায় isComplete।

অবশ্যই, আপনি এটি যুক্ত করতে পারবেন না, কারণ এটি স্থানীয় পরিবর্তনশীল। এবং অবশ্যই এটি যেহেতু স্থানীয় পরিবর্তনশীল, তাই এটির মোটেই প্রয়োজন হবে না, কারণ স্থানীয়দের স্ট্যাকের উপর রাখা হয় এবং তারা স্বাভাবিকভাবে সর্বদা "সতেজ" থাকে।

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

public static void Main(string[] args)
{
    TheHelper hlp = new TheHelper();

    var t = new Thread(hlp.Body);

    t.Start();

    Thread.Sleep(500);
    hlp.isComplete = true;
    t.Join();
    Console.WriteLine("complete!");
}

private class TheHelper
{
    public bool isComplete = false;

    public void Body()
    {
        int i = 0;

        while (!isComplete) i += 0;
    }
}

আমি এখন কল্পনা করতে পারি যে মাল্টিথ্রেডেড পরিবেশে জেআইটি সংকলক / অপ্টিমাইজার, TheHelperক্লাস প্রক্রিয়াকরণ করার সময়, পদ্ধতিটির শুরুতে কোনও রেজিস্টার বা স্ট্যাক ফ্রেমের মূলত ক্যাশে করতে পারে falseএবং Body()পদ্ধতিটি শেষ না হওয়া পর্যন্ত এটিকে কখনই রিফ্রেশ করতে পারে না। এর কারণেই কোনও গ্যারান্টি নেই যে "= সত্য" কার্যকর হওয়ার আগে থ্রেড এবং পদ্ধতিটি শেষ হবে না, সুতরাং যদি কোনও গ্যারান্টি না থাকে তবে কেন এটি ক্যাশে রাখবেন না এবং প্রতিবার এটি পড়ার পরিবর্তে একবার হ্যাপ অবজেক্টটি পড়ার পারফরম্যান্সের উত্সাহ পান get পুনরাবৃত্তির।

মূল শব্দটির volatileঅস্তিত্বই এই কারণেই ।

এই সহায়ক-বর্গটি মাল্টি-থ্রেড পরিবেশে একটি সামান্য সামান্য আরও ভাল 1) সংশোধন করার জন্য , এটি থাকা উচিত:

    public volatile bool isComplete = false;

তবে, অবশ্যই এটি যেহেতু এটি স্বয়ংক্রিয়ভাবে তৈরি কোড, আপনি এটি যুক্ত করতে পারবেন না। আরও ভাল পদ্ধতির lock()আশেপাশে কিছু পাঠ এবং লেখার জন্য যোগ করা isCompletedবা ব্যবহারের জন্য প্রস্তুত সিঙ্ক্রোনাইজেশন বা থ্রেডিং / টাস্কিং ইউটিলিটিগুলি খালি-ধাতু করার চেষ্টা না করে (যা এটি খালি ধাতব হবে না , যেহেতু এটি জিসি, জেআইটি এবং (..)) এর সাথে সিএলআরে সি # রয়েছে

ডিবাগ মোডের পার্থক্যটি সম্ভবত ঘটে কারণ ডিবাগ মোডে অনেকগুলি অপটিমাইজেশন বাদ দেওয়া হয়, সুতরাং আপনি পর্দায় যে কোডটি দেখছেন তা ডিবাগ করতে পারেন। অতএব while (!isComplete)অনুকূলিত হয় না যাতে আপনি সেখানে একটি ব্রেকপয়েন্ট নির্ধারণ করতে পারেন, এবং অতএব isCompleteপদ্ধতিটি শুরুতে কোনও রেজিস্টারে বা স্ট্যাকের সাথে আক্রমণাত্মকভাবে ক্যাশে করা হয় না এবং প্রতিটি লুপের পুনরাবৃত্তিতে হিপযুক্ত বস্তু থেকে পড়া হয়।

BTW। এটাই আমার অনুমান মাত্র। আমি এটি সংকলনের চেষ্টাও করি নি।

BTW। এটি কোনও বাগ বলে মনে হচ্ছে না; এটি একটি খুব অস্পষ্ট পার্শ্ব প্রতিক্রিয়া মত আরও। এছাড়াও, যদি আমি এটি সম্পর্কে সঠিক হয়ে থাকি তবে এটি ভাষার ঘাটতি হতে পারে - সি # কে "ভোল্টাইল" কীওয়ার্ড স্থানীয় ভেরিয়েবলগুলিতে রাখার অনুমতি দেওয়া উচিত যা বন্দী হয়ে সদস্য ক্ষেত্রে উন্নীত হয়।

1) সম্পর্কে এরিক Lippert থেকে একটি মন্তব্যের জন্য নিচে দেখুন volatileএবং / অথবা এই খুব আকর্ষণীয় যে কোড উপর নির্ভর নিশ্চিত জড়িত জটিলতা মাত্রা দেখাচ্ছে নিবন্ধটি volatileহয় নিরাপদ ..uh, ভাল ..uh, এর ঠিক আছে বলা যাক।


2
@ এরিকলিপার্ট: ওহ, এত তাড়াতাড়ি নিশ্চিত করার জন্য আপনাকে অনেক ধন্যবাদ! আপনি কীভাবে ভাবেন, ভবিষ্যতের কিছু সংস্করণে আমরা volatileক্যাপচার-টু ক্লোজার স্থানীয় ভেরিয়েবলগুলির বিকল্প পেতে পারি এমন কোনও সুযোগ আছে কি? আমি ধারণা করি সংকলক দ্বারা প্রক্রিয়া করা কিছুটা কঠিন হতে পারে ..
— কোয়েটজলক্যাটল

7
@ কোয়েটজলকোটল: শীঘ্রই যে বৈশিষ্ট্যটি যুক্ত করা হবে তা আমি বিশ্বাস করব না। এটি এমন ধরণের কোডিং যা আপনি নিরুৎসাহিত করতে চান , এবং সহজ করে তুলবেন না । এবং তদ্ব্যতীত, স্টাফগুলি অস্থির করে তোলা অগত্যা প্রতিটি সমস্যার সমাধান করে না। এখানে একটি উদাহরণ যেখানে সবকিছু অস্থির এবং প্রোগ্রামটি এখনও ভুল; আপনি বাগ খুঁজে পেতে পারেন? blog.coverity.com/2014/03/26/reordering-optimizations
— এরিক লিপার্ট

3
বুঝতে পারছিল না। আমি মাল্টিথ্রেডিং অপ্টিমাইজেশানগুলি বোঝার চেষ্টা ছেড়ে দিচ্ছি ... এটি কতটা জটিল তা উন্মাদ।
— 12'7

10
@ পিকোহ: আবারও একজন অপ্টিমাইজারের মতো ভাবুন। আপনার একটি পরিবর্তনশীল রয়েছে যা বর্ধিত তবে কখনও পড়েনি। এমন কোনও পরিবর্তনশীল যা কখনই পঠিত হয় না তা পুরোপুরি মোছা যায়।
— এরিক লিপার্ট

4
@ এরিকলিপার্ট এখন আমার মন ক্লিক করে। এই থ্রেডটি খুব তথ্যবহুল হয়েছে, আপনাকে অনেক ধন্যবাদ, সত্যই।
— পিকোহ

82

Quetzalcoatl উত্তর সঠিক। এটিতে আরও আলোকপাত করা:

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

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

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


1
মন্তব্যগুলি বর্ধিত আলোচনার জন্য নয়; এই কথোপকথন চ্যাটে সরানো হয়েছে ।
— মাদারার ঘোস্ট

14

আমি চলমান প্রক্রিয়াটির সাথে সংযুক্ত হয়েছি এবং খুঁজে পেয়েছি (যদি আমি ভুল না করি তবে আমি এটি নিয়ে খুব বেশি অনুশীলন করি না) যে Threadপদ্ধতিটি এর সাথে অনুবাদ করা হয়েছে:

debug051:02DE04EB loc_2DE04EB:                            
debug051:02DE04EB test    eax, eax
debug051:02DE04ED jz      short loc_2DE04EB
debug051:02DE04EF pop     ebp
debug051:02DE04F0 retn

eax(যার মান রয়েছে isComplete) প্রথমবার লোড করা হয় এবং কখনই সতেজ হয় না।


8

আসলেই কোনও উত্তর নয়, তবে এই বিষয়ে আরও কিছু আলোকপাত করা:

সমস্যাটি মনে হয় যখন iল্যাম্বডা দেহের অভ্যন্তরে ঘোষণা করা হয় এবং এটি কেবল অ্যাসাইনমেন্ট এক্সপ্রেশনে পড়ে read অন্যথায়, কোডটি রিলিজ মোডে ভাল কাজ করে:

  1. i ল্যাম্বডা দেহের বাইরে ঘোষণা করা:

    int i = 0; // Declared outside the lambda body
    
    var t = new Thread(() =>
    {
        while (!isComplete) { i += 0; }
    }); // Completes in release mode
  2. i অ্যাসাইনমেন্ট এক্সপ্রেশনটিতে পড়া হয় না:

    var t = new Thread(() =>
    {
        int i = 0;
        while (!isComplete) { i = 0; }
    }); // Completes in release mode
  3. i অন্য কোথাও পড়া হয়:

    var t = new Thread(() =>
    {
        int i = 0;
        while (!isComplete) { Console.WriteLine(i); i += 0; }
    }); // Completes in release mode

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

তবুও, আমি এটি নিয়ে খুব বেশি চিন্তা করব না, কারণ অনুরূপ কোডটি আসলে কোনও উদ্দেশ্য কোথায় কার্যকর করবে তা আমি দেখতে ব্যর্থ হয়েছি।


1
আমার উত্তর দেখুন, আমি বেশ নিশ্চিত যে এটি 'অস্থির' কীওয়ার্ড সম্পর্কে যা স্থানীয় ভেরিয়েবলের সাথে যুক্ত করা যায় না (যা আসলে পরে বন্ধের কোনও সদস্য ক্ষেত্রে উন্নীত হয়) ..
— কোয়েটজলক্যাটল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.