ورود

View Full Version : سوال: CriticalSection با TimeOut



یوسف زالی
دوشنبه 27 خرداد 1392, 22:50 عصر
سلام.
چطور می شه یک CriticalSection ساخت با قابلیت تایم اوت؟
یعنی بیاد سعی کنه Acquire کنه ولی اگر مثلا 3 ثانیه طول کشید و نتونست، TimeOut شه؟

MohsenB
سه شنبه 28 خرداد 1392, 00:24 صبح
سلام

میتونید یک تیکه از کدتون رو قرار بدید؟

یوسف زالی
سه شنبه 28 خرداد 1392, 01:04 صبح
procedure P1;
begin
if MyLock.TryToAcquireTimeOut(1000) then
begin
DoSomeThings;
MyLock.Release;
end
else
DoSomeThingElseForTimeOut;
end;


فکر کنید که همزمان 20 تا ترد می ریزه رو سر این پروسیجر. یکیشون به هر دلیلی در DoSomeThings ایست می کنه. بقیه چقدر باید معطل باز شدن قفل بمونن؟
باید یک راهی باشه تا بشه این رو مدیریت کرد.

MohsenB
سه شنبه 28 خرداد 1392, 02:13 صبح
سلام

منظورم تیکه ای از اصل کدتون بود تا نسبت به کدتون شاید روشهای بهتری بشه تعریف کرد . ولی در کل الان من این روش رو بذهنم میاد :

یه متغییر بولی درون کلاس تعریف کنید و یه تابع مثل زیر بنویسید :

function WaitToUnlock(iTimeOut :Integer = 1000):Boolean;
begin
while bLock do if iTimeOut > 0 then begin Dec(iTimeOut);Sleep(1); end else Exit(False);
Result:= True; bLock:= True;
end;

حالا برای مثال اینطوری ازش اسفاده کنید :

procedure P1;
begin
if WaitToUnlock(1000) then begin
DoSomeThings;
bLock:= False;
end else
DoSomeThingElseForTimeOut;
end;

موفق باشید

یوسف زالی
سه شنبه 28 خرداد 1392, 09:28 صبح
اصل برنامه در مورد استفاده اشتراکی از یک منبع Single Task هست و روش دیگه ای نداره.
سورس هم 43000 خطه. نمی شه گذاشت!!
اگر روشتون رو یک بار تریس کنید متوجه می شید که روش شما مشکل داره.
باگ:
سه تا پروسه در نظر بگیرید که میان تو P1
اولین ترد داخل منطقه بحرانی می شه و قفل رو انجام می ده.
دو ترد دیگه هر کدوم داخل حلقه می شن و منتظر آزاد شدن قفل می مونن.
ترد اول قفل رو باز می کنه
هر دو ترد این رو متوجه می شن و همزمان از حلقه خارج می شن
هر دو سعی می کنن قفل رو انجام بدن و انجام هم می دن!!!
هر دو با هم وارد منطقه ی بحرانی می شن.

دوست من، خودت تست کنی متوجه عمق مطلب می شی.
از دیروز تا به حال 5 روش رو تست کردم. فکر می کنم بشه با CreateSemaphore یا CreateMutex و توابع WaitForSingleObject یک کارهایی کرد اما روشش رو نتونستم پیاده کنم.

MohsenB
سه شنبه 28 خرداد 1392, 11:46 صبح
سلام

منظورم کل کد که نبود ، اون تیکه ای که به منطقه بحرانی نیاز داره کافیه .

من فکر میکنم کدی که گذاشتم درست باشه . منطقم اینه ببینید : وقتی شما چند سرنخ همزمان اجرا میکنید ، به معنی این نیست که هر کدوم از این سرنخ ها بصورت کاملا مجزا در پردازنده کاملا مجزا اجرا میشه ، روش کار سیستم عامل ویندوز بصورت ساده اینه که میاد از هر سرنخ تیکه ای رو اجرا میکنه و بدون اینکه کل اون اجرا شده باشه سراغ سرنخ بعدی میره . این یعنی وقتی شما یک متغییر عمومی داشته باشید وقتی سرنخی مقدار اون رو تغییر میده برای سرنخ بعدی اون مقدار تغییر کرده و اینطور نیست که در یک لحظه چند سرنخ همزمان اجرا بشن . البته فقط متغییر های صحیح و بولی محافظت شده در برابر چندسرنخی ( ThreadSafe ) هستند که ما هم از همین استفاده کردیم . اگر نگاهی به بیشتر روش های کنترل همزمانی بندازید می بینید از همین روش استفاده شده .

اگر کدتون جوریه که بشه از پشته استفاده کرد و همینطور اگر این کنترل تایم اوت رو درون کدی که بهش شک دارید قرار بدید راههای بدی نیستن .

موفق باشید

یوسف زالی
سه شنبه 28 خرداد 1392, 12:21 عصر
فکر کنم باید بهتر توضیح می دادم:


-- har do thread inja gir mikonan ta bLock true beshe
while bLock do
if iTimeOut > 0 then
begin
Dec(iTimeOut);
Sleep(1);
end
else
Exit(False);

-- har 2 thread mifahman ke bLock = false shode
-- har 2 mian inja!

Result := True;
bLock:= True;


ببینید، نمی خوام وارد کلاک پالس و این چیزا بشم. اما ممکنه هر دو ترد در زمان که بهشون اختصاص داده می شه از حلقه بیان بیرون.
شما پیش فرض نادرستی داری مبنی بر اینکه بین اجرای حلقه While و Result := true هیچ تردی استاپ نمی شه و زمان سی پی یو ازش گرفته نمی شه.
در حقیقت شما داری این دو تا دستور رو اتمیک فرض می کنی که نیست.
اگر به همین سادگی می شد که خیلی خوب بود.
من روش شما رو همراه با Critical Section به طور تلفیقی هم استفاده کردم و مشکل داشت. شاید باور نکنید اما دو دستور انتصاب پشت سر هم از نوع بولی هم لزوما اتمیک ران نمی شند و نمی شه روی کوچیک بودن فاصله ی زمانی اونها حساب باز کرد. حتی اگر فقط یک کلاک پالس فاصله داشته باشند ممکنه سیستم عامل زمان سی پی یو رو از ترد جاری برداره و بده به بک ترد دیگه. اون وقت همه چیز رو هواست.
سرعت تکرار این کار و تعداد و تایم اوت هر چه بیشتر باشه برنامه احتمال کرش شدن بیشتر داره.

یوسف زالی
سه شنبه 28 خرداد 1392, 12:23 عصر
راهی که روی کاغذ جواب داده استفاده از یک شی هست که توش یک ترد و یک صف داشته باشه و هر تردی وارد می شه رو درجا Suspend می کنه..
باید پیادش کنم ببینم در عمل چه جوابی می ده.

BORHAN TEC
سه شنبه 28 خرداد 1392, 13:51 عصر
سلام
تمام تاپیک رو نخوندم ولی اگر از نسخه های جدیدتر دلفی استفاده می کنید می توانید برای ایجاد تردهای امن(safe) از TThread.Queue استفاده کنید.
موفق باشید...

یوسف زالی
سه شنبه 28 خرداد 1392, 13:52 عصر
نه ورژنم 7 ه..

یوسف زالی
چهارشنبه 29 خرداد 1392, 11:22 صبح
تونستم خیلی به سادگی با توابع API انجامش بدم.
TryEnterCriticalSection