আমি কেন একটি লক স্টেটমেন্টের শরীরে 'অপেক্ষার' অপারেটরটি ব্যবহার করতে পারি না?


348

ল # স্টেটমেন্টের মধ্যে সি # (.NET Async CTP) এর অপেক্ষার কীওয়ার্ডটির অনুমতি নেই।

এমএসডিএন থেকে :

একটি প্রতীকী অভিব্যক্তি একটি সিঙ্ক্রোনাস ফাংশনে, ক্যোয়ারী এক্সপ্রেশনে, কোনও ব্যতিক্রম হ্যান্ডলিং স্টেটমেন্টের ক্যাচ বা অবশেষে ব্লক, লক স্টেটমেন্টের ব্লকে বা কোনও অনিরাপদ প্রসঙ্গে ব্যবহার করা যাবে না।

আমি ধরে নিয়েছি যে এটি কম্পাইলার দলের পক্ষে কোনও কারণে বাস্তবায়ন করা কঠিন বা অসম্ভব।

আমি ব্যবহারের বিবৃতিটি নিয়ে কাজ করার চেষ্টা করেছি:

class Async
{
    public static async Task<IDisposable> Lock(object obj)
    {
        while (!Monitor.TryEnter(obj))
            await TaskEx.Yield();

        return new ExitDisposable(obj);
    }

    private class ExitDisposable : IDisposable
    {
        private readonly object obj;
        public ExitDisposable(object obj) { this.obj = obj; }
        public void Dispose() { Monitor.Exit(this.obj); }
    }
}

// example usage
using (await Async.Lock(padlock))
{
    await SomethingAsync();
}

তবে এটি প্রত্যাশার মতো কাজ করে না। মনিটরের কল। আমার আশেপাশে আমার কাজের অবিশ্বাস্যতা এবং লক স্টেটমেন্টে প্রত্যাশিত বিবৃতিগুলির অনুমতি না পাওয়ার কারণটি কোনওভাবেই সম্পর্কিত suspect

কেউ কি জানেন যে কেন লক স্টেটমেন্টের শিরোনামে অপেক্ষা করতে দেওয়া হয় না?


27
আমি কল্পনা করব যে এটির অনুমতি না পাওয়ার কারণটি আপনি খুঁজে পেয়েছেন।
asawyer

3
আমি এই লিঙ্কটিটি প্রস্তাব করতে পারি: hanselman.com/blog/… এবং এটির একটি: ব্লগস.এমএসএনএন
হ্যান্স

আমি কেবল এসিঙ্ক প্রোগ্রামিং সম্পর্কে আরও কিছু জানতে এবং শিখতে শুরু করছি। আমার ডাব্লুপিএফ অ্যাপ্লিকেশনগুলিতে অসংখ্য অচলাবস্থার পরে, আমি এই নিবন্ধটি অ্যাসিঙ্ক প্রোগ্রামিং অনুশীলনে একটি দুর্দান্ত সুরক্ষক হিসাবে খুঁজে পেয়েছি। msdn.microsoft.com/en-us/magazine/...
সি Tewalt

লকটি অ্যাসিঙ্ক অ্যাক্সেস প্রতিরোধ করার জন্য ডিজাইন করা হয়েছে যখন অ্যাসিঙ্ক অ্যাক্সেস আপনার কোডটি ভেঙে দেবে, আপনি যদি কোনও লকের অভ্যন্তরে
অ্যাসিঙ্ক

উত্তর:


366

আমি ধরে নিয়েছি যে এটি কম্পাইলার দলের পক্ষে কোনও কারণে বাস্তবায়ন করা কঠিন বা অসম্ভব।

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

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

সঠিক, আপনি আবিষ্কার করেছেন যে কেন আমরা এটিকে অবৈধ করে তুলেছি। লকের ভিতরে অপেক্ষা করা হ'ল ডেডলক তৈরির একটি রেসিপি।

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

সবচেয়ে খারাপ বিষয়, কোডটি অন্য থ্রেডে পুনরায় শুরু হতে পারে (উন্নত পরিস্থিতিতে; সাধারণত আপনি যে থ্রেডটি অপেক্ষা করেছিলেন তা আবার ধরেন তবে প্রয়োজনীয় নয়) যে ক্ষেত্রে আনলকটি যে থ্রেডটি নিয়েছিল তার চেয়ে আলাদা থ্রেডে তালা আনলক করবে case লক আউট এটা কি ভাল ধারণা? না।

আমি নোট করেছি যে একই কারণে একটি এর yield returnঅভ্যন্তরে করাও একটি "নিকৃষ্ট অনুশীলন" lock। এটি আইনী, তবে আমি আশা করি আমরা এটি অবৈধ করে তুলেছি। আমরা "অপেক্ষা" করার জন্য একই ভুল করতে যাচ্ছি না।


188
আপনি কীভাবে এমন একটি পরিস্থিতি পরিচালনা করবেন যেখানে আপনাকে ক্যাশে প্রবেশ ফিরিয়ে আনতে হবে এবং যদি প্রবেশের অস্তিত্ব না থাকে তবে আপনাকে অবিচ্ছিন্নভাবে বিষয়বস্তু গণনা করতে হবে তারপরে আর কেউ আপনাকে কল করবে না তা নিশ্চিত করে + এন্ট্রি ফিরিয়ে দিন?
সফটলিয়ন

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

4
@ গ্যারেথ উইলসন: আমি ডেডলক নিয়ে কথা বলেছিলাম কারণ প্রশ্ন করা প্রশ্নটি ছিল ডেডলক সম্পর্কে । আপনি সঠিক যে উদ্ভট পুনরায় প্রবেশের বিষয়গুলি সম্ভব এবং সম্ভবত বলে মনে হয়।
এরিক লিপার্ট

11
@ এরিক লিপার্ট আপনি SemaphoreSlim.WaitAsyncএই উত্তর পোস্ট করার পরে ক্লাসটি .NET ফ্রেমওয়ার্কে যুক্ত হয়েছিলো তা দেখে, আমি মনে করি আমরা নিরাপদে ধরে নিতে পারি যে এটি এখন সম্ভব is তা নির্বিশেষে, এই ধরনের নির্মাণ বাস্তবায়নের অসুবিধা সম্পর্কে আপনার মন্তব্যগুলি এখনও সম্পূর্ণ বৈধ।
কনটাঙ্গো

7
"কলকারীর অপেক্ষারত প্রত্যাবর্তন নিয়ন্ত্রণের সময়টি এবং পদ্ধতিটি পুনরায় চালু হওয়ার সময়ের মধ্যে স্বেচ্ছাসেবক কোড চলে" - অবশ্যই এটি কোনও কোডের ক্ষেত্রে সত্য, এমনকি অসিঙ্ক / অপেক্ষার অনুপস্থিতিতে, বহুবিধ প্রসঙ্গে: অন্য থ্রেডগুলি যে কোনও স্থানে নির্বিচার কোড প্রয়োগ করতে পারে সময়, এবং যথেচ্ছ কোড বলে আপনি বলেছিলেন "" লক অর্ডার ইনভার্শনগুলি তৈরি করে এমন লকগুলি বের করা হতে পারে, এবং তাই ডেডলকগুলি। " তাহলে কেন এ্যাসিঙ্ক / প্রতীক্ষার সাথে এটি বিশেষ তাত্পর্যপূর্ণ? আমি দ্বিতীয় পয়েন্টটি বুঝতে পারি যে "কোডটি আবার অন্য থ্রেডে আবার শুরু হতে পারে" async / অপেক্ষার বিশেষ তাত্পর্যপূর্ণ।
বাচার

291

SemaphoreSlim.WaitAsyncপদ্ধতি ব্যবহার করুন ।

 await mySemaphoreSlim.WaitAsync();
 try {
     await Stuff();
 } finally {
     mySemaphoreSlim.Release();
 }

10
এই পদ্ধতিটি সম্প্রতি নেট নেট ফ্রেমওয়ার্কে প্রবর্তিত হওয়ায়, আমি মনে করি আমরা ধরে নিতে পারি যে একটি অ্যাসিঙ্ক / প্রতীক্ষিত বিশ্বে লক করার ধারণাটি এখন যথেষ্ট প্রমাণিত।
কনটাঙ্গো

5
আরও কিছু তথ্যের জন্য, এই নিবন্ধটিতে "সেমফোরস্লিম" পাঠ্যের সন্ধান করুন: অ্যাসিঙ্ক /
অ্যাওয়েট

1
@ জামেসকো যদি এই সমস্ত কাজগুলির ফলাফলের জন্য অপেক্ষা করে থাকে তবে Stuffআমি এর আশেপাশে কোনও উপায় দেখতে পাচ্ছি না ...
ওহাদ স্নাইডার

7
এটি যেমন mySemaphoreSlim = new SemaphoreSlim(1, 1)কাজ করার জন্য আরম্ভ করা উচিত নয় lock(...)?
সের্গেই

3
এই উত্তরের বর্ধিত সংস্করণ যুক্ত করা হয়েছে: stackoverflow.com/a/50139704/1844247
সের্গেই

67

মূলত এটি করা ভুল জিনিস হবে।

দুটি উপায়ে এই হয় পারে বাস্তবায়িত হবে:

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

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

সুতরাং মূলত এখানে দুটি প্রতিযোগিতার প্রয়োজনীয়তা রয়েছে - আপনার এখানে প্রথমটি করার চেষ্টা করা উচিত নয় , এবং আপনি যদি দ্বিতীয় পন্থা অবলম্বন করতে চান তবে অপেক্ষার এক্সপ্রেশন দিয়ে পৃথক দুটি লক ব্লক রেখে কোডটি আরও পরিষ্কার করতে পারবেন:

// Now it's clear where the locks will be acquired and released
lock (foo)
{
}
var result = await something;
lock (foo)
{
}

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


5
আপনি SemaphoreSlim.WaitAsyncএই উত্তর পোস্ট করার পরে ক্লাসটি .NET ফ্রেমওয়ার্কে যুক্ত হয়েছিলো তা দেখে, আমি মনে করি আমরা নিরাপদে ধরে নিতে পারি যে এটি এখন সম্ভব is তা নির্বিশেষে, এই ধরনের নির্মাণ বাস্তবায়নের অসুবিধা সম্পর্কে আপনার মন্তব্যগুলি এখনও সম্পূর্ণ বৈধ।
কনটাঙ্গো

7
@Contango আচ্ছা যে না বেশ একই জিনিস। বিশেষত, সেমফোর একটি নির্দিষ্ট থ্রেডের সাথে আবদ্ধ নয়। এটি লক করার অনুরূপ লক্ষ্য অর্জন করে, তবে উল্লেখযোগ্য পার্থক্য রয়েছে।
জন স্কিটি

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

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

41

এটি এই উত্তরের কেবল একটি এক্সটেনশন ।

using System;
using System.Threading;
using System.Threading.Tasks;

public class SemaphoreLocker
{
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

    public async Task LockAsync(Func<Task> worker)
    {
        await _semaphore.WaitAsync();
        try
        {
            await worker();
        }
        finally
        {
            _semaphore.Release();
        }
    }
}

ব্যবহার:

public class Test
{
    private static readonly SemaphoreLocker _locker = new SemaphoreLocker();

    public async Task DoTest()
    {
        await _locker.LockAsync(async () =>
        {
            // [asyn] calls can be used within this block 
            // to handle a resource by one thread. 
        });
    }
}

1
tryব্লকের বাইরে সেমফোর লক পাওয়া বিপজ্জনক হতে পারে - যদি এর মধ্যে একটি ব্যতিক্রম ঘটে WaitAsyncএবং tryসেমফোরটি কখনই প্রকাশিত হবে না (অচলাবস্থা)। অন্যদিকে, ব্লকে চলন্ত WaitAsyncকলটি tryআরেকটি সমস্যা উপস্থাপন করবে, যখন কোনও লক অধিগ্রহণ না করেই সেম্যাফোরটি ছেড়ে দেওয়া যেতে পারে। : সংশ্লিষ্ট থ্রেড যেখানে এই সমস্যা ব্যাখ্যা করা হয়েছে দেখুন stackoverflow.com/a/61806749/7889645
AndreyCh

16

এটি http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx , http://winrtstoragehelper.codeplex.com/ , উইন্ডোজ 8 অ্যাপ স্টোর এবং নেট নেট 4.5 রেফারেন্স করে

এখানে আমার কোণ এখানে:

অ্যাসিঙ্ক / অপেক্ষারত ভাষার বৈশিষ্ট্যটি অনেকগুলি বিষয়কে মোটামুটি সহজ করে তোলে তবে এটি এমন একটি দৃশ্যেরও পরিচয় দেয় যা অ্যাসিঙ্ক কলগুলি ব্যবহার করা এত সহজ হওয়ার আগে খুব কমই ঘটেছিল: পুনরায় প্রবেশ করা।

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

এখানে একটি উইন্ডোজ 8 অ্যাপ স্টোর অ্যাপ্লিকেশনটিতে আমি আসলাম এমন একটি বাস্তব দৃশ্য: আমার অ্যাপ্লিকেশনটির দুটি ফ্রেম রয়েছে: একটি ফ্রেম থেকে আসা এবং ছেড়ে যাওয়া আমি ফাইল / স্টোরেজে কিছু ডেটা লোড / নিরাপদ করতে চাই। OnNavigatedTo / from ইভেন্টগুলি সঞ্চয় এবং লোডিংয়ের জন্য ব্যবহৃত হয়। সঞ্চয় ও লোডিং কিছু অ্যাসিঙ্ক ইউটিলিটি ফাংশন (যেমন: http://winrtstoragehelper.codeplex.com/ ) দ্বারা সম্পন্ন হয় । ফ্রেম 1 থেকে ফ্রেম 2 এ বা অন্য দিকে নেভিগেট করার সময়, অ্যাসিঙ্ক লোড এবং নিরাপদ ক্রিয়াকলাপগুলি ডাকা এবং প্রতীক্ষিত। ইভেন্ট হ্যান্ডলারগুলি অ্যাসিঙ্ক ফিরতে শূন্য হয়ে যায় => তারা অপেক্ষা করতে পারে না।

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

আমার জন্য একটি সর্বনিম্ন সমাধান হ'ল ব্যবহার এবং একটি এসিঙ্কলকের মাধ্যমে ফাইল অ্যাক্সেস সুরক্ষিত করা।

private static readonly AsyncLock m_lock = new AsyncLock();
...

using (await m_lock.LockAsync())
{
    file = await folder.GetFileAsync(fileName);
    IRandomAccessStream readStream = await file.OpenAsync(FileAccessMode.Read);
    using (Stream inStream = Task.Run(() => readStream.AsStreamForRead()).Result)
    {
        return (T)serializer.Deserialize(inStream);
    }
}

দয়া করে নোট করুন যে তার লকটি মূলত কেবলমাত্র একটি লক দিয়ে ইউটিলিটির জন্য সমস্ত ফাইল অপারেশন লক করে রাখে, যা অহেতুক শক্তিশালী তবে এটি আমার দৃশ্যের জন্য দুর্দান্ত কাজ করে।

এখানে আমার পরীক্ষার প্রকল্পটি রয়েছে: http://winrtstoragehelper.codeplex.com/ এর মূল সংস্করণের জন্য উইন্ডোজ 8 অ্যাপ স্টোর অ্যাপ এবং আমার সংশোধিত সংস্করণ যা স্টিফেন টব http: //blogs.msdn থেকে অ্যাসিঙ্কলক ব্যবহার করে । com / b / pfxteam / সংরক্ষণাগার / 2012/02/12 / 10266988.aspx

আমি এই লিঙ্কটিও সুপারিশ করতে পারি: http://www.hanselman.com/blog/ComperingTwoTechnificationsInNETAsynchronousCoordinationPrimitives.aspx


7

স্টিফেন Taub এই প্রশ্নের একটি সমাধান বাস্তবায়ন করেছে, দেখুন বিল্ডিং এসিঙ্ক সমন্বয় প্রিমিটিভের, পার্ট 7: AsyncReaderWriterLock

স্টিফেন তৌবকে ইন্ডাস্ট্রিতে খুব বেশি সম্মান করা হয়, তাই তাঁর লেখার যে কোনও কিছুই সম্ভবত দৃ be় হতে পারে।

তিনি তার ব্লগে যে কোডটি পোস্ট করেছেন তা পুনরুত্পাদন করব না, তবে কীভাবে এটি ব্যবহার করব তা আমি আপনাকে দেখাব:

/// <summary>
///     Demo class for reader/writer lock that supports async/await.
///     For source, see Stephen Taub's brilliant article, "Building Async Coordination
///     Primitives, Part 7: AsyncReaderWriterLock".
/// </summary>
public class AsyncReaderWriterLockDemo
{
    private readonly IAsyncReaderWriterLock _lock = new AsyncReaderWriterLock(); 

    public async void DemoCode()
    {           
        using(var releaser = await _lock.ReaderLockAsync()) 
        { 
            // Insert reads here.
            // Multiple readers can access the lock simultaneously.
        }

        using (var releaser = await _lock.WriterLockAsync())
        {
            // Insert writes here.
            // If a writer is in progress, then readers are blocked.
        }
    }
}

.NET ফ্রেমওয়ার্কে বেকড এমন কোনও পদ্ধতি আপনি চাইলে SemaphoreSlim.WaitAsyncপরিবর্তে ব্যবহার করুন। আপনি কোনও পাঠক / লেখক লক পাবেন না, তবে আপনি চেষ্টা করেছেন এবং বাস্তবায়ন পরীক্ষা করেছেন।


এই কোডটি ব্যবহারে কোনও সতর্কতা আছে কিনা তা জানতে আগ্রহী। যদি কেউ এই কোডটি দিয়ে কোনও সমস্যা প্রদর্শন করতে পারে তবে আমি জানতে চাই। যাইহোক, সত্যটি হ'ল asNnc / প্রতীক্ষিত লকিংয়ের ধারণাটি অবশ্যই SemaphoreSlim.WaitAsyncNET ফ্রেমওয়ার্কের মতো কার্যকরভাবে প্রমাণিত । এই সমস্ত কোডটি হ'ল একটি পাঠক / লেখক লক ধারণা যুক্ত করা।
কনটাঙ্গো

3

হুম, দেখতে দেখতে কুরুচিপূর্ণ, মনে হচ্ছে কাজ করছে।

static class Async
{
    public static Task<IDisposable> Lock(object obj)
    {
        return TaskEx.Run(() =>
            {
                var resetEvent = ResetEventFor(obj);

                resetEvent.WaitOne();
                resetEvent.Reset();

                return new ExitDisposable(obj) as IDisposable;
            });
    }

    private static readonly IDictionary<object, WeakReference> ResetEventMap =
        new Dictionary<object, WeakReference>();

    private static ManualResetEvent ResetEventFor(object @lock)
    {
        if (!ResetEventMap.ContainsKey(@lock) ||
            !ResetEventMap[@lock].IsAlive)
        {
            ResetEventMap[@lock] =
                new WeakReference(new ManualResetEvent(true));
        }

        return ResetEventMap[@lock].Target as ManualResetEvent;
    }

    private static void CleanUp()
    {
        ResetEventMap.Where(kv => !kv.Value.IsAlive)
                     .ToList()
                     .ForEach(kv => ResetEventMap.Remove(kv));
    }

    private class ExitDisposable : IDisposable
    {
        private readonly object _lock;

        public ExitDisposable(object @lock)
        {
            _lock = @lock;
        }

        public void Dispose()
        {
            ResetEventFor(_lock).Set();
        }

        ~ExitDisposable()
        {
            CleanUp();
        }
    }
}

0

আমি একটি মনিটর ব্যবহার করার চেষ্টা করেছি (নীচের কোডটি) যা কাজ করে বলে মনে হচ্ছে তবে এতে একটি গোটচা আছে ... যখন আপনার একাধিক থ্রেড থাকবে তখন তা দেবে ... সিস্টেম.ট্রেডিং ynসিনক্রোনাইজেশন লকএক্সেপশন অবজেক্ট সিঙ্ক্রোনাইজেশন পদ্ধতিটি কোডের একটি অচ্ছিন্নীকৃত ব্লক থেকে ডেকে আনা হয়েছিল।

using System;
using System.Threading;
using System.Threading.Tasks;

namespace MyNamespace
{
    public class ThreadsafeFooModifier : 
    {
        private readonly object _lockObject;

        public async Task<FooResponse> ModifyFooAsync()
        {
            FooResponse result;
            Monitor.Enter(_lockObject);
            try
            {
                result = await SomeFunctionToModifyFooAsync();
            }
            finally
            {
                Monitor.Exit(_lockObject);
            }
            return result;
        }
    }
}

এর আগে আমি কেবল এটি করছিলাম, তবে এটি একটি এএসপি.এনইটি নিয়ন্ত্রণকারীতে ছিল সুতরাং এটি একটি অচলাবস্থার ফলস্বরূপ।

public async Task<FooResponse> ModifyFooAsync() { lock(lockObject) { return SomeFunctionToModifyFooAsync.Result; } }

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