সি # ইভেন্ট এবং থ্রেড সুরক্ষা


237

হালনাগাদ

সি # 6 হিসাবে, এই প্রশ্নের উত্তরটি হ'ল:

SomeEvent?.Invoke(this, e);

আমি নিম্নলিখিত পরামর্শটি প্রায়শই শুনি / পড়ি:

কোনও ইভেন্টের জন্য এটি পরীক্ষা করা nullএবং ফায়ার করার আগে সর্বদা তার অনুলিপি তৈরি করুন । এটি থ্রেডিংয়ের সাথে একটি সম্ভাব্য সমস্যাটি দূর করবে যেখানে ইভেন্টটি nullযেখানে নাল পরীক্ষা করবে এবং যেখানে আপনি ইভেন্টটি চালাচ্ছেন তার মাঝখানে ঠিক সেখানে অবস্থান করবে:

// Copy the event delegate before checking/calling
EventHandler copy = TheEvent;

if (copy != null)
    copy(this, EventArgs.Empty); // Call any handlers on the copied list

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

তবে ইতিমধ্যে, এই সমস্যাটি এমনকি ঘটে যাওয়ার জন্য, অন্য একটি থ্রেড অবশ্যই এর মতো কিছু করেছে:

// Better delist from event - don't want our handler called from now on:
otherObject.TheEvent -= OnTheEvent;
// Good, now we can be certain that OnTheEvent will not run...

আসল ক্রম এই মিশ্রণ হতে পারে:

// Copy the event delegate before checking/calling
EventHandler copy = TheEvent;

// Better delist from event - don't want our handler called from now on:
otherObject.TheEvent -= OnTheEvent;    
// Good, now we can be certain that OnTheEvent will not run...

if (copy != null)
    copy(this, EventArgs.Empty); // Call any handlers on the copied list

OnTheEventলেখকটি সদস্যতা বাতিল করার পরে যে দৃষ্টিকোণ চলছে , তা এখনও এড়াতে তারা বিশেষভাবে সদস্যতা নিল। নিশ্চয় সত্যিই কি প্রয়োজন হয় যথাযথ সুসংগত একটি কাস্টম ঘটনা বাস্তবায়ন addএবং removeaccessors। এবং তদ্ব্যতীত কোনও ইভেন্টের সময় গুলি চালানোর সময় একটি লক রাখা থাকলে সম্ভাব্য অচলাবস্থার সমস্যা রয়েছে।

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

(এবং কেবলমাত্র delegate { }সদস্য ঘোষণায় খালি বরাদ্দ করা কি খুব সহজ নয় যাতে আপনার কখনই nullপ্রথম স্থানে যাচাইয়ের দরকার পড়ে না ?)

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

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

এরিক লিপার্টের ব্লগ পোস্টগুলির প্রতিক্রিয়া হিসাবে আপডেট করুন:

সুতরাং ইভেন্ট হ্যান্ডলারগুলির সম্পর্কে আমি একটি বড় জিনিসটি মিস করেছি: "ইভেন্টটি হস্তান্তরকারীদের ইভেন্টটি সাবস্ক্রাইব করার পরেও ডাকা হওয়ার আগেই দৃust় হওয়া দরকার", এবং অবশ্যই আমাদের কেবল ইভেন্টটির সম্ভাবনা সম্পর্কে যত্ন নেওয়া দরকার প্রতিনিধি হচ্ছে nullইভেন্ট হ্যান্ডলারগুলিতে কি সেই প্রয়োজনীয়তাটি কোথাও নথিভুক্ত করা হয়েছে?

এবং তাই: "এই সমস্যাটি সমাধানের অন্যান্য উপায় রয়েছে; উদাহরণস্বরূপ, হ্যান্ডলারের একটি খালি পদক্ষেপের জন্য আরম্ভ করা যা কখনই সরানো হয় না a তবে নাল চেক করা মানক নিদর্শন" "

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

অবশ্যই এটি অবশ্যই হতে হবে (জোন স্কিটের পরামর্শ অনুসারে) এটি ঠিক। নেট 1.x পরামর্শ যা মারা যায় নি, যেমনটি 2005 সালে করা উচিত ছিল?


4
এই প্রশ্নটি কিছুক্ষণ আগে অভ্যন্তরীণ আলোচনায় উঠে আসে; আমি কিছু সময়ের জন্য এটি ব্লগ করার ইচ্ছা ছিল। বিষয়ে আমার পোস্টটি এখানে: ইভেন্ট এবং রেস
এরিক লিপার্ট

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

3
@ আরকাগেরার - আসলে থ্রেড জড়িত না থাকলেও দ্বিতীয় ইস্যুটি মাঝেমধ্যে ইভেন্ট হ্যান্ডলারটি মোকাবেলা করতে হবে। যদি কোনও ইভেন্ট হ্যান্ডলার অন্য হ্যান্ডলারটিকে বর্তমানে পরিচালনা করা ইভেন্টটি থেকে সদস্যতা রোধ করতে বলে তবে এটি ঘটতে পারে তবে ২ য় গ্রাহক তারপরেই ইভেন্টটি গ্রহণ করবেন (কারণ এটি পরিচালনা করার সময় এটি সদস্যতা বাতিল করা হয়েছিল)।
ড্যানিয়েল আরউইকার

3
শূন্য গ্রাহকগণের সাথে ইভেন্টে সাবস্ক্রিপশন যুক্ত করা, ইভেন্টের একমাত্র সাবস্ক্রিপশনটি সরিয়ে দেওয়া, শূন্য গ্রাহকগণের সাথে একটি ইভেন্টের জন্য অনুরোধ করা এবং ঠিক একজন গ্রাহকের সাথে ইভেন্টের আহ্বান করা, অন্যান্য সংখ্যার সংখ্যার সাথে জড়িত / অপসারণ / অনুরোধ করা পরিস্থিতিগুলির চেয়ে আরও দ্রুত ক্রিয়াকলাপ are গ্রাহক। একটি ডামি প্রতিনিধি যুক্ত করা সাধারণ ক্ষেত্রে ধীর করে দেয়। সি # এর সাথে আসল সমস্যাটি হ'ল এর নির্মাতারা EventName(arguments)ইভেন্টটির প্রতিনিধিটিকে শর্তহীনভাবে আহ্বান করার সিদ্ধান্ত নিয়েছেন , কেবলমাত্র অ-শূন্য হলে ডেলিগেটকে আহবান করার চেয়ে (নাল হলে কিছুই করবেন না)।
সুপারক্যাট

উত্তর:


100

শর্তের কারণে প্রথম অংশে আপনি যে অপ্টিমাইজেশনটির কথা বলছেন তা জেআইটিকে করার অনুমতি নেই। আমি জানি এটি কিছুক্ষণ আগে একটি স্পেক্টর হিসাবে উত্থাপিত হয়েছিল, তবে এটি বৈধ নয়। (আমি কিছুক্ষণ আগে জো ডফি বা ভ্যানস মরিসনের সাথে এটি পরীক্ষা করেছিলাম; কোনটি আমি মনে করতে পারি না)

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

এবং হ্যাঁ, অবশ্যই একটি রেসের শর্ত আছে - তবে সর্বদা থাকবে। ধরুন আমরা কেবল কোডটি এতে পরিবর্তন করেছি:

TheEvent(this, EventArgs.Empty);

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

একটি খালি প্রতিনিধি ব্যবহার অবশ্যই নালিশতা পরীক্ষা এড়ায়, কিন্তু রেসের শর্তটি ঠিক করে না। এটির গ্যারান্টিও দেয় না যে আপনি সর্বদা চলকের সর্বশেষতম মান "দেখেন"।


4
জো ডাফির "উইন্ডোজ অন কনকন্টেন্ট প্রোগ্রামিং" প্রশ্নের জেআইটি অপটিমাইজেশন এবং মেমরির মডেল দিকটি কভার করে; দেখতে code.logos.com/blog/2008/11/events_and_threads_part_4.html
ব্র্যাডলি Grainger

2
আমি "স্ট্যান্ডার্ড" পরামর্শটি সি -2-এর পূর্বের 2-এর প্রাক্কলনের ভিত্তিতে এটিকে মেনে নিয়েছি এবং আমি কারও সাথে এটির বিরোধিতা শুনছি না। আপনার ইভেন্ট আরগগুলি ইনস্ট্যান্ট করা সত্যই ব্যয়বহুল না হলে আপনার ইভেন্টের ঘোষণার শেষে '= ডেলিগেট {}' চাপুন এবং তারপরে আপনার ইভেন্টগুলিকে সরাসরি কল করুন যেন তারা পদ্ধতি; তাদের কখনই নাল বরাদ্দ করবেন না। (হ্যান্ডলারটি নিশ্চিত করার বিষয়ে আমি যে অন্যান্য জিনিসপত্র নিয়ে এসেছি তা ডেলিস্টের পরে ডাকা হয় না, এটি সমস্ত অপ্রাসঙ্গিক ছিল এবং এটি একক থ্রেড কোডের জন্যও নিশ্চিত করা অসম্ভব, উদাহরণস্বরূপ যদি হ্যান্ডলার 1 হ্যান্ডলারের 2 টি ডিলিস্ট করতে বলে, হ্যান্ডলার 2 এখনও কল হবে) পরবর্তী।)
ড্যানিয়েল আরউইকার

2
একমাত্র সমস্যার ক্ষেত্রে (সর্বদা হিসাবে) স্ট্রাক্টস, যেখানে আপনি নিশ্চিত করতে পারবেন না যে তাদের সদস্যদের নাল মান ব্যতীত অন্য কোনও কিছুর দ্বারা তদন্ত করা হবে। কিন্তু স্ট্রাকস স্তন্যপান।
ড্যানিয়েল আরউইকার

1
খালি প্রতিনিধি সম্পর্কে, এই প্রশ্নটিও দেখুন: stackoverflow.com/questions/170907/…
ভ্লাদিমির

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

52

আমি দেখছি প্রচুর লোক এটি করার এক্সটেনশন পদ্ধতির দিকে যাচ্ছে ...

public static class Extensions   
{   
  public static void Raise<T>(this EventHandler<T> handler, 
    object sender, T args) where T : EventArgs   
  {   
    if (handler != null) handler(sender, args);   
  }   
}

এটি আপনাকে ইভেন্টটি বাড়ানোর জন্য আরও সুন্দর সিনট্যাক্স দেয় ...

MyEvent.Raise( this, new MyEventArgs() );

এবং স্থানীয় কপিটিও ছাড়ায় যেহেতু এটি পদ্ধতি কল সময়ে ধরা পড়ে।


9
আমি সিনট্যাক্সটি পছন্দ করি তবে আসুন পরিষ্কার হয়ে যাক ... এটি কোনও বাসি হ্যান্ডলার অনিবন্ধিত হওয়ার পরেও অনুরোধ করার পরেও সমস্যার সমাধান করে না। এটি কেবল নাল ডেরেফারেন্স সমস্যার সমাধান করে। আমি সিনট্যাক্সটি পছন্দ করার সময়, আমি প্রশ্ন করি যে এটি সত্যর চেয়ে আরও ভাল কিনা: সর্বজনীন ইভেন্ট ইভেন্টহ্যান্ডলার <T> মাই ইভেন্ট = মুছুন {}; ... MyEvent (এটি, নতুন MyEventArgs ()); এটি খুব কম ঘর্ষণ সমাধান যা এর সরলতার জন্য আমি পছন্দ করি।
সাইমন গিলবি

@ সিমন আমি বিভিন্ন মানুষ এই বিষয়ে বিভিন্ন কথা বলতে দেখছি। আমি এটি পরীক্ষা করেছি এবং আমি যা করেছি তা ইঙ্গিত দেয় যে এটি নাল হ্যান্ডলার ইস্যুটিকে পরিচালনা করে। এমনকি যদি আসল সিন্ডটি হ্যান্ডলারটির পরে ইভেন্ট থেকে নিবন্ধভুক্ত হয়! = নাল চেক করা, ইভেন্টটি এখনও উত্থাপিত হয় এবং কোনও ব্যতিক্রম ছুঁড়ে না দেওয়া হয়।
জেপি আলিওটো

হ্যাঁ, এই প্রশ্ন CF: stackoverflow.com/questions/192980/...
Benjol

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

কীভাবে এটি ভিবি.এনইটি থেকে কল করা যেতে পারে? বা 'রাইসইভেন্ট' ইতিমধ্যে মাল্টি-থ্রেডিং দৃশ্যের জন্য যত্নশীল?

35

"কেন 'স্ট্যান্ডার্ড প্যাটার্ন' স্পষ্ট-নাল চেক করা হয়?"

আমি সন্দেহ করি এর কারণ হ'ল নাল চেকটি আরও পারফরম্যান্ট।

আপনার ইভেন্টগুলি তৈরি হওয়ার সময় আপনি যদি সর্বদা কোনও খালি প্রতিনিধি সাবস্ক্রাইব করেন তবে কিছু ওভারহেড থাকবে:

  • খালি প্রতিনিধি নির্মাণের ব্যয়।
  • এটি ধারণ করার জন্য একটি প্রতিনিধি চেইন নির্মাণের ব্যয়।
  • প্রতিবার ইভেন্টটি উত্থাপিত হওয়ার সময় অর্থহীন প্রতিনিধিদের আহ্বানের ব্যয়।

(নোট করুন যে ইউআই কন্ট্রোলগুলিতে প্রায়শই প্রচুর সংখ্যক ইভেন্ট থাকে, যার মধ্যে বেশিরভাগটি কখনই সাবস্ক্রাইব হয় না each প্রতিটি ইভেন্টে একটি ডামি গ্রাহক তৈরি করার পরে এবং অনুরোধ করা এটি সম্ভবত একটি উল্লেখযোগ্য পারফরম্যান্স হিট হতে পারে))

সাবস্ক্রাইব-খালি-প্রতিনিধি পদ্ধতির প্রভাব দেখতে আমি কিছু অভিশাপ সম্পাদনামূলক পরীক্ষা করেছি এবং এখানে আমার ফলাফলগুলি রয়েছে:

Executing 50000000 iterations . . .
OnNonThreadSafeEvent took:      432ms
OnClassicNullCheckedEvent took: 490ms
OnPreInitializedEvent took:     614ms <--
Subscribing an empty delegate to each event . . .
Executing 50000000 iterations . . .
OnNonThreadSafeEvent took:      674ms
OnClassicNullCheckedEvent took: 674ms
OnPreInitializedEvent took:     2041ms <--
Subscribing another empty delegate to each event . . .
Executing 50000000 iterations . . .
OnNonThreadSafeEvent took:      2011ms
OnClassicNullCheckedEvent took: 2061ms
OnPreInitializedEvent took:     2246ms <--
Done

নোট করুন যে শূন্য বা এক জন গ্রাহকের ক্ষেত্রে (ইউআই নিয়ন্ত্রণের ক্ষেত্রে সাধারণ, যেখানে ইভেন্টগুলি প্রচুর পরিমাণে হয়), খালি প্রতিনিধি নিয়ে প্রাক-সূচনা হওয়া ইভেন্টটি ধীর গতিযুক্ত (50 মিলিয়নেরও বেশি পুনরাবৃত্তি ...)

আরও তথ্য এবং উত্স কোডের জন্য, এই প্রশ্নটি জিজ্ঞাসা করার ঠিক আগের দিনই প্রকাশিত .NET ইভেন্টের অনুরোধের থ্রেড সুরক্ষার জন্য এই ব্লগ পোস্টটি দেখুন (!)

(আমার পরীক্ষার সেট আপটি ত্রুটিযুক্ত হতে পারে তাই উত্স কোডটি ডাউনলোড করে নির্দ্বিধায় নিজে নিজে দেখে নিন Any কোনও প্রতিক্রিয়া অনেকই প্রশংসিত))


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

13
এবং আপনার পরিসংখ্যানগুলি বিন্দুটি খুব ভালভাবে প্রমাণ করে: ওভারহেড উত্থাপিত ইভেন্টের (প্রি-থিম বনাম ক্লাসিক-নাল) প্রতি আড়াই ন্যানোসেকেন্ডস (!!!) এ নেমে আসে। এটি বাস্তব কাজের জন্য প্রায় অ্যাপ্লিকেশনগুলিতে অন্বেষণযোগ্য হবে, তবে ইভেন্টের সিংহভাগ ব্যবহারের বিষয়টি জিইউআই ফ্রেমওয়ার্কগুলিতে রয়েছে, আপনাকে উইনফর্মস ইত্যাদির স্ক্রিনের অংশগুলি পুনরায় রঙ করার ব্যয়ের সাথে এটি তুলনা করতে হবে, তাই এটি বাস্তব সিপিইউ কাজের প্রলয় এবং সংস্থানগুলির জন্য অপেক্ষারত আরও অদৃশ্য হয়ে যায়। যাইহোক, কঠোর পরিশ্রমের জন্য আপনি আমার কাছ থেকে +1 পান। :)
ড্যানিয়েল আরউইকার

1
@ ড্যানিয়েলআরওয়িকার ঠিক বলেছেন, আপনি আমাকে জনসাধারণের ইভেন্টে বিশ্বাসী হতে প্রেরণা দিয়েছেন WrapperDoneHandler OnWrapperDone = (x, y) => {}; মডেল.
মিকি পার্লস্টাইন

1
ইভেন্ট শূন্য, এক, বা দুটি গ্রাহক রয়েছে এমন ক্ষেত্রে Delegate.Combine/ Delegate.Removeজুটির সময় দেওয়া ভাল হতে পারে ; যদি কেউ একই প্রতিনিধি উদাহরণটি বার বার যোগ করে এবং সরিয়ে দেয়, মামলাগুলির মধ্যে ব্যয়ের পার্থক্যটি বিশেষত উচ্চারণ করা হবে যেহেতু Combineএকটি বিশেষ যুক্তিযুক্ত যুক্তিটি null(কেবল অন্যটিকে ফিরিয়ে দেওয়া) Removeদ্রুত হয় এবং যখন দুটি যুক্তি হয় তখন খুব দ্রুত হয় সমান (কেবল নাল ফেরান)
সুপারক্যাট

12

আমি সত্যিই এই পড়া উপভোগ - না! যদিও আমার প্রয়োজন এটি ইভেন্ট নামক সি # বৈশিষ্ট্যটির সাথে কাজ করা!

সংকলকটিতে কেন এটি ঠিক করবেন না? আমি জানি এমএস ব্যক্তিরা যারা এই পোস্টগুলি পড়েছেন, সুতরাং দয়া করে এটি শিখাবেন না!

1 - নাল ইস্যু ) ইভেন্টগুলি কেন করা হবে না? প্রথম স্থানে নাল পরিবর্তে বেশিরভাগই? নাল চেক বা = delegate {}ঘোষণার উপর আটকে থাকার জন্য কোডের কতগুলি লাইন সংরক্ষণ করা হবে ? খালি কেসটি সংকলকটি পরিচালনা করতে দাও, আইই কিছুই করবেন না! যদি এগুলি ইভেন্টের স্রষ্টার কাছে গুরুত্বপূর্ণ হয় তবে তারা চেক করতে পারে mp কার্যকর এবং তারা যা যা যত্ন করে তা করতে পারে! অন্যথায় সমস্ত নাল চেক / প্রতিনিধি যোগ সমস্যা হ্যাক হয়!

সত্যিই আমি প্রতিটি ইভেন্টের সাথে এটি করতে করতে ক্লান্ত হয়ে পড়েছি - ওরফে বয়লারপ্লেট কোড!

public event Action<thisClass, string> Some;
protected virtual void DoSomeEvent(string someValue)
{
  var e = Some; // avoid race condition here! 
  if(null != e) // avoid null condition here! 
     e(this, someValue);
}

2 - রেস কন্ডিশনের সমস্যা ) আমি এরিকের ব্লগ পোস্টটি পড়েছি, আমি সম্মত হই যে এইচ (হ্যান্ডলার) হ্যান্ডলিং করা উচিত যখন এটি নিজেকে অবলম্বন করে, তবে ইভেন্টটি কি অপরিবর্তনীয় / থ্রেডকে নিরাপদ করা যায় না? আইই, এর তৈরিতে একটি লক পতাকা সেট করুন, যাতে যখনই এটি ডাকা হয়, এটি কার্যকর হওয়ার সময় এটিতে সমস্ত সাবস্ক্রাইব এবং আন-সাবস্ক্রাইব করে লক করে রাখে?

উপসংহার ,

আধুনিক ভাষাগুলি কি আমাদের মতো এই সমস্যাগুলি সমাধান করার কথা নয়?


সম্মত, সংকলকটিতে এর জন্য আরও ভাল সমর্থন থাকা উচিত। ততক্ষণে , আমি একটি পোস্টশার্প দিক তৈরি করেছি যা পোস্ট-সংকলন পদক্ষেপে এটি করে । :)
স্টিভেন জিউরিস 0

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

@supercat। তবে, "আরও খারাপ" মন্তব্যটি বেশ অ্যাপ্লিকেশন নির্ভর। অতিরিক্ত পতাকা ছাড়াই খুব কড়া লকিংয়ের বিকল্প নেই যখন এটি বিকল্প? যদি ইভেন্ট হ্যান্ডলিং থ্রেডটি অন্য থ্রেডের জন্য অপেক্ষা করে থাকে তবে একটি অচলাবরণ ঘটতে হবে (এটি সাবস্ক্রাইব / সাবস্ক্রাইব করছে) যেহেতু লকগুলি একই থ্রেডটি পুনরায় প্রবেশকারী এবং মূল ইভেন্ট হ্যান্ডলারের মধ্যে একটি সাবস্ক্রাইব / সাবস্ক্রাইব অবরুদ্ধ করা হবে না। ইভেন্ট হ্যান্ডলারের অংশ হিসাবে যদি ক্রস থ্রেড অপেক্ষা করে থাকে তবে আমি পুনরায় কাজ করতে পছন্দ করব এমন ডিজাইনের একটি অংশ হবে। আমি এমন একটি সার্ভার-সাইড অ্যাপ কোণ থেকে আসছি যার অনুমানযোগ্য নিদর্শন রয়েছে।
ক্রোকুসেক

2
@crokusek: বিশ্লেষণ করা প্রয়োজন প্রমাণ করে একটি সিস্টেম অচলাবস্থা মুক্ত সহজ যদি কেশ যে সব প্রতিটি লক সংযোগের সময় একটি নির্দেশ গ্রাফ কোন চক্র হতে হবে পারে যখন এটি অনুষ্ঠিত হচ্ছে প্রয়োজন হতে [চক্র অভাব সিস্টেম প্রমাণ অচলাবস্থা মুক্ত]। লকটি রাখা থাকাকালীন স্বেচ্ছাসেবক কোডটি প্রবেশ করার অনুমতি দিলে সেই লক থেকে যেকোন লক স্বেচ্ছাসেবক কোড অর্জন করতে পারে যা "সম্ভবত প্রয়োজন হতে" গ্রাফের একটি প্রান্ত তৈরি করবে (সিস্টেমের প্রতিটি লক নয়, তবে এটি খুব বেশি দূরে নয়) )। চক্রের ফলস্বরূপ অস্তিত্ব বোঝাতে পারে না যে অচলাবস্থা ঘটবে, কিন্তু ...
সুপারক্যাট

1
... এটি প্রমাণ করতে পারে না যে এটি বিশ্লেষণের প্রয়োজনীয়তার স্তরটি যথেষ্ট পরিমাণে বৃদ্ধি করবে।
সুপারক্যাট

8

সঙ্গে সি # 6 এবং উপরে, কোড ব্যবহার করে নতুন সরলীকৃত যেতে পারে ?.হিসাবে অপারেটর:

TheEvent?.Invoke(this, EventArgs.Empty);

এখানে এমএসডিএন ডকুমেন্টেশন রয়েছে।


5

সি # এর মাধ্যমে সিএলআর বইটিতে জেফ্রি রিখরারের মতে সঠিক পদ্ধতিটি হ'ল:

// Copy a reference to the delegate field now into a temporary field for thread safety
EventHandler<EventArgs> temp =
Interlocked.CompareExchange(ref NewMail, null, null);
// If any methods registered interest with our event, notify them
if (temp != null) temp(this, e);

কারণ এটি একটি রেফারেন্স কপি জোর করে। আরও তথ্যের জন্য, বইয়ের তার ইভেন্ট বিভাগটি দেখুন।


আমি স্মিথ অনুপস্থিত থাকতে পারি, তবে ইন্টারলকড omp কমপ্লে এক্সচেঞ্জ যদি নুলারফেরান এক্সপ্লেশনকে ছুড়ে ফেলে তবে এর প্রথম যুক্তিটি যদি নাল হয় তবে আমরা ঠিক এড়াতে চাই। msdn.microsoft.com/en-us/library/bb297966.aspx
Kniganapolke

1
Interlocked.CompareExchangeএটি যদি কোনওভাবে শূন্য হয়ে যায় তবে ব্যর্থ হবে ref, তবে এটি refকোনও স্টোরেজ অবস্থানে (যেমন NewMail) উপস্থিত রয়েছে এবং যা প্রাথমিকভাবে নাল রেফারেন্স ধারণ করে তা পাস করার মতো নয় ।
সুপারক্যাট

4

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

private readonly object eventMutex = new object();

private event EventHandler _onEvent = null;

public event EventHandler OnEvent
{
  add
  {
    lock(eventMutex)
    {
      _onEvent += value;
    }
  }

  remove
  {
    lock(eventMutex)
    {
      _onEvent -= value;
    }
  }

}

private void HandleEvent(EventArgs args)
{
  lock(eventMutex)
  {
    if (_onEvent != null)
      _onEvent(args);
  }
}

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


প্রকৃতপক্ষে, আমি দেখতে পাচ্ছি যে অন্য কেউ এখানে খুব অনুরূপ প্যাটার্ন ব্যবহার করছেন: stackoverflow.com/questions/3668953/…
অ্যাশ

2

এই অনুশীলনটি নির্দিষ্ট ক্রিয়াকলাপ কার্যকর করার বিষয়ে নয়। এটি আসলে নাল রেফারেন্স ব্যতিক্রম এড়ানো সম্পর্কে।

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

দ্রষ্টব্য: দৌড় শর্তটি ঠিক করা সম্ভবত হ্যান্ডলারটি চালিত হওয়া উচিত কিনা তা একটি সিঙ্ক্রোনাস ফ্ল্যাগ ট্র্যাক ব্যবহারের সাথে জড়িত


আমি সেই সমস্যার সমাধান চাইছি না। আমি ভাবছি কেন ইভেন্টের ফায়ারিংয়ের আশেপাশে অতিরিক্ত কোড-মেস স্প্রে করার জন্য কেন বিস্তৃত পরামর্শ দেওয়া হচ্ছে, যখন এটি কেবলমাত্র একটি শূন্য ব্যতিক্রম এড়িয়ে চলে যখন কোনও শনাক্তকরণের শক্ত দশা থাকা অবস্থায় এখনও বিদ্যমান থাকবে।
ড্যানিয়েল আরউইকার

1
ভাল যে আমার বিষয় ছিল। তারা না যত্ন জাতি অবস্থা সম্পর্কে। তারা কেবল নাল রেফারেন্স ব্যতিক্রম সম্পর্কে যত্নশীল। আমি আমার উত্তরে এটি সম্পাদনা করব।
dss539

আমার বক্তব্য হচ্ছে: কেন এটা নাল রেফারেন্স ব্যতিক্রম যত্নের জানার জন্য হবে এবং এখনো না race অবস্থা চিন্তা করেন?
ড্যানিয়েল আরউইকার

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

2
@ ডিএসএস ৫৯৯: যদিও কেউ ইভেন্ট ইভেন্ট কাঠামোটি শেষ না হওয়া অবধি সাবস্ক্রিপশন অনুরোধগুলিকে ব্লক করবে এমন ইভেন্ট ফ্রেমওয়ার্ক ডিজাইন করতে পারে, যেমন একটি নকশা কোনও ইভেন্টের জন্য (এমনকি কোনও ইভেন্টের মতো কিছু Unload) নিরাপদে অন্য ইভেন্টের জন্য কোনও অবজেক্টের সাবস্ক্রিপশন বাতিল করে দেয়। কদর্য। আরও সহজভাবে বলা ভাল যে ইভেন্টের সদস্যতা রোধের অনুরোধগুলি ইভেন্টগুলি "অবশেষে" সাবস্ক্রাইব করে দেবে এবং ইভেন্টের গ্রাহকরা যখন তাদের অনুরোধ করা হয়েছিল যে তাদের করার জন্য কোন কার্যকর কিছু আছে কিনা তা পরীক্ষা করা উচিত।
সুপারক্যাট

1

তাই আমি এখানে পার্টিতে কিছুটা দেরি করছি। :)

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

এটি মনে রেখে, একটি সমাধান বলতে হবে "ভাল, শূন্য গ্রাহকরা নাল দ্বারা প্রতিনিধিত্ব করে।" তারপরে আপনার ব্যয়বহুল ক্রিয়াকলাপ সম্পাদনের আগে নাল চেকটি সম্পাদন করুন। আমি মনে করি এটি করার অন্য কোনও উপায় হ'ল ডেলিগেট ধরণে একটি কাউন্ট সম্পত্তি থাকত, সুতরাং আপনি কেবলমাত্র ব্যয়বহুল অপারেশন সম্পাদন করতে পারতেন যদি myDelegate.Count> 0. একটি গণনা সম্পত্তি ব্যবহার করা কিছুটা সুন্দর প্যাটার্ন যা মূল সমস্যাটি সমাধান করে অপ্টিমাইজেশনের অনুমতি দেওয়ার, এবং এতে নুলারফেরান এক্সসেপশন তৈরি না করেই ডাকা হতে সক্ষম হওয়ার দুর্দান্ত সম্পত্তি রয়েছে।

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

দ্রষ্টব্য: এটি খাঁটি জল্পনা। আমি নেট নেট ভাষা বা সিএলআর এর সাথে জড়িত নই।


আমি ধরে নিলাম আপনার অর্থ "খালি প্রতিনিধি ব্যবহারের পরিবর্তে ..." আপনি ইতিমধ্যে যা পরামর্শ করবেন তা করতে পারেন, একটি ইভেন্ট শূন্য প্রতিনিধিটির সাথে শুরু করে। প্রাথমিক খালি প্রতিনিধি তালিকার মধ্যে যদি একমাত্র জিনিস হয় তবে পরীক্ষা (MyEvent.GetInvocationList ()। দৈর্ঘ্য == 1) সত্য হবে। এখনও প্রথমে একটি অনুলিপি তৈরি করার প্রয়োজন হবে না। যদিও আমি মনে করি আপনার বর্ণিত কেসটি যাইহোক অত্যন্ত বিরল হবে।
ড্যানিয়েল আরউইকার

আমি মনে করি আমরা এখানে প্রতিনিধিদের এবং ইভেন্টগুলির ধারণাগুলি বিলোপ করছি। আমার ক্লাসে যদি আমার একটি ইভেন্ট ফু থাকে তবে বাহ্যিক ব্যবহারকারীরা যখন MyType.Foo + = / - = কল করেন তারা আসলে অ্যাড_ফু () এবং সরান_ফু () পদ্ধতিগুলি কল করছেন। যাইহোক, আমি যখন ক্লাসটির সংজ্ঞা দেওয়া হয় তখন থেকেই আমি ফুটিকে উল্লেখ করি তবে আমি আসলে অন্তর্নিহিত প্রতিনিধিটিকে সরাসরি উল্লেখ করছি, অ্যাড_ফু () এবং সরান_ফু () পদ্ধতিগুলি নয়। এবং ইভেন্টহ্যান্ডলারলিস্টের মতো ধরণের অস্তিত্বের সাথে, ডেলিগেট এবং ইভেন্ট এমনকি একই জায়গায় হওয়া বাধ্যতামূলক কিছুই নেই। আমার প্রতিক্রিয়াতে "মনে রাখবেন" অনুচ্ছেদটি দ্বারা এটি বোঝানো হয়েছিল।
লেভি

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

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

@ লেভি: সি # ইভেন্টগুলি যেভাবে পরিচালনা করে তা আমি সত্যিই পছন্দ করি না। আমার ড্রথাররা থাকলে প্রতিনিধিটিকে ইভেন্ট থেকে আলাদা নাম দেওয়া হত। শ্রেণীর বাইরে থেকে, ইভেন্টের নামের একমাত্র অনুমোদিত ক্রিয়াকলাপ +=এবং -=। শ্রেণীর মধ্যে, অনুমতিযোগ্য ক্রিয়াকলাপগুলির মধ্যে অন্তর্ভুক্তি (অন্তর্নির্মিত নাল চেক সহ) অনুরোধ করা, বিরুদ্ধে পরীক্ষা করা nullবা সেট করা অন্তর্ভুক্ত ছিল null। অন্য যে কোনও কিছুর জন্য, একজনকে সেই প্রতিনিধিটি ব্যবহার করতে হবে যার নামটি কোনও নির্দিষ্ট উপসর্গ বা প্রত্যয় সহ ইভেন্টের নাম হবে।
সুপারক্যাট

0

একক থ্রেডযুক্ত আবেদনকারীর জন্য, আপনি সংশোধন করছেন এটি কোনও সমস্যা নয়।

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

খালি ডেলিগেট ব্যবহার করা সমস্যার সমাধান করে, তবে ইভেন্টটির প্রতিটি কলকে একটি পারফরম্যান্স হিট করে এবং সম্ভবত জিসি জড়িয়ে থাকতে পারে।

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

আপনি যদি অস্থায়ী পরিবর্তনশীল না ব্যবহার করেন, এবং খালি প্রতিনিধি এবং কেউ সদস্যতা ছাড়েন না, আপনি একটি নাল রেফারেন্স ব্যতিক্রম পান, যা মারাত্মক, তাই আমি মনে করি ব্যয়টি মূল্যবান।


0

আমি কখনই এটিকে আসলেই খুব বেশি সমস্যা হিসাবে বিবেচনা করি নি কারণ আমি সাধারণত আমার পুনরায় ব্যবহারযোগ্য উপাদানগুলিতে স্থির পদ্ধতি (ইত্যাদি) এর এই ধরণের সম্ভাব্য থ্রেডিং খারাপের বিরুদ্ধে রক্ষা করি এবং আমি স্থির ইভেন্টগুলি করি না।

আমি কি এটা ভুল করছি?


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

আমার সাধারণ পদ্ধতির স্থির পদ্ধতি বাদে কলকারীর কাছে সিঙ্ক্রোনাইজেশন ছেড়ে যাওয়া। আমি যদি কলার হয়ে থাকি তবে আমি সেই উচ্চ স্তরে সিঙ্ক্রোনাইজ করব। (এমন কোনও বিষয় ব্যতীত যার একমাত্র উদ্দেশ্য অবশ্যই সিঙ্ক্রোনাইজড অ্যাক্সেস পরিচালনা করছে :) :))
গ্রেগ ডি

@ গ্রেগড যা নির্ভর করে যে পদ্ধতিটি কতটা জটিল এবং এটি কী ডেটা ব্যবহার করে। যদি এটি আভ্যন্তরীণ সদস্যদেরকে প্রভাবিত করে এবং আপনি থ্রেডেড / টাস্কযুক্ত অবস্থায় চালানোর সিদ্ধান্ত নেন তবে আপনি অনেক ক্ষতি করতে
চলেছেন

0

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

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

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

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

সত্যিই, আমি মনে করি ডেলিগেট শ্রেণিটি অবিশ্রয়যোগ্য। মাল্টিকাস্টডেলিগেটে সংযুক্তি / রূপান্তর একটি বিশাল ভুল ছিল, কারণ এটি কার্যকরভাবে কোনও ঘটনার (কার্যকর) সংজ্ঞাটি এমন কিছু থেকে কার্যকরভাবে পরিবর্তিত করে যা একটি সময়ে তাত্ক্ষণিকভাবে ঘটে যায় এমন একটি সময়ে, যা একটি টাইমস্প্যানের মধ্যে ঘটে। এই জাতীয় পরিবর্তনের জন্য একটি সিঙ্ক্রোনাইজেশন প্রক্রিয়া প্রয়োজন যা যুক্তিযুক্তভাবে এটি একটি একক তাত্ক্ষণিকর মধ্যে আবার ভেঙে যেতে পারে, তবে মাল্টিকাস্টডেলিগেটে এমন কোনও ব্যবস্থার অভাব রয়েছে। সিঙ্ক্রোনাইজেশনের পুরো টাইমস্প্যানটি অন্তর্ভুক্ত করা উচিত বা ইভেন্টটি ঘটে তাত্ক্ষণিকভাবে হওয়া উচিত, যাতে কোনও অ্যাপ্লিকেশন কোনও ইভেন্ট হ্যান্ডলিং শুরু করার জন্য সিঙ্ক্রোনাইজ করা সিদ্ধান্ত নেয়, এটি সম্পূর্ণরূপে (লেনদেনের মাধ্যমে) হ্যান্ডেলিং শেষ করে। মাল্টিকাস্টডেলিগেট / ডেলিগেট হাইব্রিড ক্লাস যে ব্ল্যাক বক্স সহ, এটি অসম্ভবের কাছাকাছি, তাইএকটি একক গ্রাহক ব্যবহার মেনে চলে এবং / অথবা যে একটি সমন্বয়সাধন হ্যান্ডেল যে গ্রহণ করা যেতে পারে যখন হ্যান্ডলার শৃঙ্খল ব্যবহৃত হচ্ছে / নিয়ন্ত্রণ করা MulticastDelegate আপনার নিজস্ব ধরনের বাস্তবায়ন । আমি এটির পরামর্শ দিচ্ছি, কারণ বিকল্পটি হ'ল আপনার সমস্ত হ্যান্ডলারের মধ্যে সংযোজন / লেনদেনের-অখণ্ডতা বাস্তবায়ন করা হবে, যা হাস্যকর / অযথা জটিল।


[1] "সময়ে একক তাত্ক্ষণিক" ঘটে এমন কোনও কার্যকর ইভেন্ট হ্যান্ডলার নেই happens সমস্ত ক্রিয়াকলাপের একটি টাইমস্প্যান রয়েছে। যে কোনও একক হ্যান্ডলারের সম্পাদন করতে পদক্ষেপগুলির একটি অপ্রয়োজনীয় ক্রম থাকতে পারে। হ্যান্ডলারের একটি তালিকা সমর্থন করে কিছুই পরিবর্তন হয় না।
ড্যানিয়েল আরউইকার

[২] ইভেন্ট চালিত হওয়ার সময় একটি লক ধরে রাখা সম্পূর্ণ উন্মাদতা। এটি অনিবার্যভাবে অচলাবস্থার দিকে নিয়ে যায়। উত্সটি লক এ নিয়ে যায়, আগুনের ঘটনা ঘটে, ডুবকে লুক বি বের করে, এখন দুটি লক ধরে আছে। যদি অন্য থ্রেডের কিছু ক্রিয়াকলাপের ফলে লকগুলি বিপরীত ক্রমে সরিয়ে নেওয়া হয়? যখন লক করার দায়িত্বটি আলাদাভাবে নকশা করা / পরীক্ষিত উপাদানগুলির মধ্যে ভাগ করা হয় (যা ইভেন্টগুলির পুরো বিন্দু)?
ড্যানিয়েল আরউইকার

[]] এগুলির কোনও বিষয়ই কোনওভাবেই সাধারণ মাল্টিকাস্ট প্রতিনিধি / ইভেন্টগুলির উপাদানগুলির একক থ্রেডযুক্ত রচনায় বিশেষত জিইউআই ফ্রেমওয়ার্কগুলিতে সর্বাত্মক উপযোগিতা হ্রাস করে না। এই ব্যবহারের ক্ষেত্রে ইভেন্টের ব্যবহারের সিংহভাগ জুড়ে। ইভেন্টগুলিকে একটি ফ্রি-থ্রেডযুক্ত পদ্ধতিতে ব্যবহার করা প্রশ্নবিদ্ধ মূল্য; এটি কোনওভাবেই তাদের নকশা বা প্রাসঙ্গিক ক্ষেত্রে যেখানে তারা উপলব্ধি করে তাদের স্পষ্টত উপকারিতা অকার্যকর করে না।
ড্যানিয়েল আরউইকার

[4] থ্রেডস + সিঙ্ক্রোনাস ইভেন্টগুলি মূলত একটি লাল রঙের হেরিং। সারিবদ্ধ অ্যাসিনক্রোনাস যোগাযোগের পথ।
ড্যানিয়েল আরউইকার

[1] আমি পরিমাপ করা সময়কে উল্লেখ করছি না ... আমি পারমাণবিক ক্রিয়াকলাপের কথা বলছিলাম, যা তাত্ক্ষণিকভাবে তাত্ক্ষণিকভাবে ঘটে ... এবং এর অর্থ হ'ল ঘটনাটি ঘটে যাওয়ার সময় তারা যে জাতীয় উত্সগুলি ব্যবহার করছে তার সাথে জড়িত অন্য কিছুই পরিবর্তন করতে পারে না কারণ এটি একটি লক দিয়ে সিরিয়ালাইজড।
ট্রায়ঙ্কো

0

দয়া করে এখানে একবার দেখুন: http://www.danielfortunov.com/software/%24daniel_fortunovs_adventures_in_software_development/2009/04/23/net_event_invocation_thread_safety এটি সঠিক সমাধান এবং সর্বদা অন্যান্য কাজের ক্ষেত্রের পরিবর্তে ব্যবহার করা উচিত।

“আপনি নিশ্চিত করতে পারেন যে অভ্যন্তরীণ আহ্বান তালিকার সর্বদা একটি না-বেনাম পদ্ধতি দিয়ে প্রাথমিকভাবে কমপক্ষে একজন সদস্য রয়েছে। যেহেতু কোনও বহিরাগত দলের বেনামে পদ্ধতিতে উল্লেখ থাকতে পারে না, কোনও বহিরাগত পক্ষই পদ্ধতিটি মুছে ফেলতে পারে না, তাই প্রতিনিধি কখনই বাতিল হবে না "- প্রোগ্রামিং। নেট উপাদানসমূহ, ২ য় সংস্করণ, জুভাল লওয়ের

public static event EventHandler<EventArgs> PreInitializedEvent = delegate { };  

public static void OnPreInitializedEvent(EventArgs e)  
{  
    // No check required - event will never be null because  
    // we have subscribed an empty anonymous delegate which  
    // can never be unsubscribed. (But causes some overhead.)  
    PreInitializedEvent(null, e);  
}  

0

আমি বিশ্বাস করি না যে প্রশ্নটি সি # "ইভেন্ট" টাইপের মধ্যে সীমাবদ্ধ। সেই সীমাবদ্ধতা অপসারণ করে, চাকাটিকে কিছুটা পুনরায় উদ্ভাবন এবং এই লাইনগুলি বরাবর কিছু না করে কেন?

নিরাপদে ইভেন্ট থ্রেড উত্থাপন - সেরা অনুশীলন

  • কোনও উত্থানের মধ্যে থাকা অবস্থায় কোনও থ্রেড থেকে সাব সাবস্ক্রাইব / সাবস্ক্রাইব করার ক্ষমতা (রেস শর্ত সরানো)
  • অপারেটর ক্লাস স্তরে + = এবং - = এর জন্য ওভারলোড।
  • জেনেরিক কলার-সংজ্ঞায়িত প্রতিনিধি

0

একটি দরকারী আলোচনার জন্য ধন্যবাদ। আমি সম্প্রতি এই সমস্যাটিতে কাজ করছি এবং নিম্নলিখিত ক্লাসটি তৈরি করেছি যা কিছুটা ধীর গতিযুক্ত, তবে নিষ্পত্তিযোগ্য অবজেক্টগুলিতে কলিং এড়ানোর অনুমতি দেয়।

এখানে মূল বিষয়টি হ'ল অনুরোধের তালিকাটি এমনকি ইভেন্ট উত্থাপনের পরেও পরিবর্তন করা যেতে পারে।

/// <summary>
/// Thread safe event invoker
/// </summary>
public sealed class ThreadSafeEventInvoker
{
    /// <summary>
    /// Dictionary of delegates
    /// </summary>
    readonly ConcurrentDictionary<Delegate, DelegateHolder> delegates = new ConcurrentDictionary<Delegate, DelegateHolder>();

    /// <summary>
    /// List of delegates to be called, we need it because it is relatevely easy to implement a loop with list
    /// modification inside of it
    /// </summary>
    readonly LinkedList<DelegateHolder> delegatesList = new LinkedList<DelegateHolder>();

    /// <summary>
    /// locker for delegates list
    /// </summary>
    private readonly ReaderWriterLockSlim listLocker = new ReaderWriterLockSlim();

    /// <summary>
    /// Add delegate to list
    /// </summary>
    /// <param name="value"></param>
    public void Add(Delegate value)
    {
        var holder = new DelegateHolder(value);
        if (!delegates.TryAdd(value, holder)) return;

        listLocker.EnterWriteLock();
        delegatesList.AddLast(holder);
        listLocker.ExitWriteLock();
    }

    /// <summary>
    /// Remove delegate from list
    /// </summary>
    /// <param name="value"></param>
    public void Remove(Delegate value)
    {
        DelegateHolder holder;
        if (!delegates.TryRemove(value, out holder)) return;

        Monitor.Enter(holder);
        holder.IsDeleted = true;
        Monitor.Exit(holder);
    }

    /// <summary>
    /// Raise an event
    /// </summary>
    /// <param name="args"></param>
    public void Raise(params object[] args)
    {
        DelegateHolder holder = null;

        try
        {
            // get root element
            listLocker.EnterReadLock();
            var cursor = delegatesList.First;
            listLocker.ExitReadLock();

            while (cursor != null)
            {
                // get its value and a next node
                listLocker.EnterReadLock();
                holder = cursor.Value;
                var next = cursor.Next;
                listLocker.ExitReadLock();

                // lock holder and invoke if it is not removed
                Monitor.Enter(holder);
                if (!holder.IsDeleted)
                    holder.Action.DynamicInvoke(args);
                else if (!holder.IsDeletedFromList)
                {
                    listLocker.EnterWriteLock();
                    delegatesList.Remove(cursor);
                    holder.IsDeletedFromList = true;
                    listLocker.ExitWriteLock();
                }
                Monitor.Exit(holder);

                cursor = next;
            }
        }
        catch
        {
            // clean up
            if (listLocker.IsReadLockHeld)
                listLocker.ExitReadLock();
            if (listLocker.IsWriteLockHeld)
                listLocker.ExitWriteLock();
            if (holder != null && Monitor.IsEntered(holder))
                Monitor.Exit(holder);

            throw;
        }
    }

    /// <summary>
    /// helper class
    /// </summary>
    class DelegateHolder
    {
        /// <summary>
        /// delegate to call
        /// </summary>
        public Delegate Action { get; private set; }

        /// <summary>
        /// flag shows if this delegate removed from list of calls
        /// </summary>
        public bool IsDeleted { get; set; }

        /// <summary>
        /// flag shows if this instance was removed from all lists
        /// </summary>
        public bool IsDeletedFromList { get; set; }

        /// <summary>
        /// Constuctor
        /// </summary>
        /// <param name="d"></param>
        public DelegateHolder(Delegate d)
        {
            Action = d;
        }
    }
}

এবং ব্যবহারটি হ'ল:

    private readonly ThreadSafeEventInvoker someEventWrapper = new ThreadSafeEventInvoker();
    public event Action SomeEvent
    {
        add { someEventWrapper.Add(value); }
        remove { someEventWrapper.Remove(value); }
    }

    public void RaiseSomeEvent()
    {
        someEventWrapper.Raise();
    }

পরীক্ষা

আমি এটি নিম্নলিখিত পদ্ধতিতে পরীক্ষা করেছি। আমার কাছে একটি থ্রেড রয়েছে যা এই জাতীয় সামগ্রী তৈরি করে এবং ধ্বংস করে:

var objects = Enumerable.Range(0, 1000).Select(x => new Bar(foo)).ToList();
Thread.Sleep(10);
objects.ForEach(x => x.Dispose());

একটি Bar(শ্রোতার অবজেক্ট) কনস্ট্রাক্টারে আমি সাবস্ক্রাইব করি SomeEvent(যা উপরে প্রদর্শিত হিসাবে প্রয়োগ করা হয়েছে) এবং এতে সাবস্ক্রাইব করুন Dispose:

    public Bar(Foo foo)
    {
        this.foo = foo;
        foo.SomeEvent += Handler;
    }

    public void Handler()
    {
        if (disposed)
            Console.WriteLine("Handler is called after object was disposed!");
    }

    public void Dispose()
    {
        foo.SomeEvent -= Handler;
        disposed = true;
    }

এছাড়াও আমার কাছে কয়েকটা থ্রেড রয়েছে যা লুপে ইভেন্ট বাড়ায়।

এই সমস্ত ক্রিয়াগুলি একই সাথে সঞ্চালিত হয়: অনেক শ্রোতা তৈরি এবং ধ্বংস হয় এবং একই সময়ে ইভেন্টটি চালানো হয়।

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

আপনি কি মনে করেন?


আমার কাছে যথেষ্ট ভালো লাগছে। যদিও আমি মনে করি আপনার পরীক্ষার প্রয়োগের disposed = trueআগে foo.SomeEvent -= Handlerএটি একটি মিথ্যা ইতিবাচক উত্পাদন ঘটানো সম্ভব (তত্ত্বের ক্ষেত্রে) হতে পারে । তবে এগুলি বাদ দিয়ে কয়েকটি জিনিস আপনি পরিবর্তন করতে চাইতে পারেন। আপনি সত্যিই try ... finallyলকগুলির জন্য ব্যবহার করতে চান - এটি আপনাকে কেবল থ্রেড-নিরাপদই নয়, গর্ভপাত-সুরক্ষিত করতে সহায়তা করবে। আপনি তখন সেই নির্বোধ থেকে মুক্তি পেতে পারেন তা উল্লেখ করার দরকার নেই try catch। আর তুমি প্রতিনিধি পাস চেক করছি না Add/ Remove- এটা হতে পারে null(যদি আপনি সোজা চলে নিক্ষেপ করা উচিত Add/ Remove)।
লুয়ান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.