আমি একজন জুনিয়র বিকাশকারী, সফ্টওয়্যারটির জন্য একটি আপডেট লেখার বিষয়ে কাজ করছি যা কোনও তৃতীয় পক্ষের সমাধান থেকে ডেটা গ্রহণ করে, এটি একটি ডেটাবেজে সংরক্ষণ করে এবং তারপরে অন্য তৃতীয় পক্ষের সমাধানের জন্য ডেটা শর্ত করে। আমাদের সফ্টওয়্যার একটি উইন্ডোজ পরিষেবা হিসাবে চলমান।
পূর্ববর্তী সংস্করণ থেকে কোডটি দেখছি, আমি এটি দেখতে পাচ্ছি:
static Object _workerLocker = new object();
static int _runningWorkers = 0;
int MaxSimultaneousThreads = 5;
foreach(int SomeObject in ListOfObjects)
{
lock (_workerLocker)
{
while (_runningWorkers >= MaxSimultaneousThreads)
{
Monitor.Wait(_workerLocker);
}
}
// check to see if the service has been stopped. If yes, then exit
if (this.IsRunning() == false)
{
break;
}
lock (_workerLocker)
{
_runningWorkers++;
}
ThreadPool.QueueUserWorkItem(SomeMethod, SomeObject);
}
যুক্তিটি সুস্পষ্ট বলে মনে হচ্ছে: থ্রেড পুলে রুমের জন্য অপেক্ষা করুন, পরিষেবাটি বন্ধ হয়নি তা নিশ্চিত করুন, তারপরে থ্রেডের কাউন্টারটি বাড়িয়ে দিন এবং কাজটি সারি করুন। তারপরে কল করা একটি স্টেটমেন্টের ভিতরে _runningWorkers
হ্রাস করা হয় ।SomeMethod()
lock
Monitor.Pulse(_workerLocker)
আমার প্রশ্ন হ'ল:
একটি কোডের অভ্যন্তরে সমস্ত কোডকে ভাগ করে নেওয়ার কোনও সুবিধা আছে কি lock
:
static Object _workerLocker = new object();
static int _runningWorkers = 0;
int MaxSimultaneousThreads = 5;
foreach (int SomeObject in ListOfObjects)
{
// Is doing all the work inside a single lock better?
lock (_workerLocker)
{
// wait for room in ThreadPool
while (_runningWorkers >= MaxSimultaneousThreads)
{
Monitor.Wait(_workerLocker);
}
// check to see if the service has been stopped.
if (this.IsRunning())
{
ThreadPool.QueueUserWorkItem(SomeMethod, SomeObject);
_runningWorkers++;
}
else
{
break;
}
}
}
দেখে মনে হচ্ছে, এটি অন্যান্য থ্রেডগুলির জন্য কিছুটা বেশি অপেক্ষা করতে পারে, তবে তারপরে মনে হচ্ছে একক লজিক্যাল ব্লকে বারবার লক করা কিছুটা সময়সাপেক্ষও হবে। তবে, আমি মাল্টি-থ্রেডিংয়ে নতুন, তাই আমি ধরে নিচ্ছি যে এখানে অন্যান্য উদ্বেগ রয়েছে যেগুলি সম্পর্কে আমি অজানা।
_workerLocker
লক হয়ে যাওয়া কেবলমাত্র অন্য কোনও জায়গাগুলিতেই রয়েছে SomeMethod()
এবং কেবল হ্রাসের উদ্দেশ্যে _runningWorkers
, এবং তারপরে লগিং এবং ফিরে আসার আগে শূন্যে যাওয়ার foreach
সংখ্যা অপেক্ষা করার জন্য _runningWorkers
।
কোন সাহায্যের জন্য ধন্যবাদ।
সম্পাদনা 4/8/15
Semaphore ব্যবহারের সুপারিশের জন্য @ ডেলানকে ধন্যবাদ। কোডটি হয়ে যায়:
static int MaxSimultaneousThreads = 5;
static Semaphore WorkerSem = new Semaphore(MaxSimultaneousThreads, MaxSimultaneousThreads);
foreach (int SomeObject in ListOfObjects)
{
// wait for an available thread
WorkerSem.WaitOne();
// check if the service has stopped
if (this.IsRunning())
{
ThreadPool.QueueUserWorkItem(SomeMethod, SomeObject);
}
else
{
break;
}
}
WorkerSem.Release()
ভিতরে বলা হয় SomeMethod()
।
SomeMethod
, উপরের "লক" বিভাগটি নতুন থ্রেডটি SomeMethod
চালানো শুরু হওয়ার কমপক্ষে বা তারপরে ছেড়ে দেওয়া হবে ।
Monitor.Wait()
লকটি প্রকাশ এবং পুনরায় অধিগ্রহণের উদ্দেশ্য যাতে অন্য কোনও উত্স ( SomeMethod
, এই ক্ষেত্রে) এটি ব্যবহার করতে পারে। অন্য প্রান্তে, SomeMethod
লকটি গ্রহণ করে, কাউন্টারটি হ্রাস করে এবং তারপরে কলগুলি Monitor.Pulse()
প্রশ্নবিদ্ধ পদ্ধতিতে লকটি ফিরিয়ে দেয়। আবার এটি আমার নিজের বোঝাপড়া।
Monitor.Wait
লকটি প্রকাশ করে। আমি ডক্সটি একবার দেখার পরামর্শ দিই।