PDA

View Full Version : سوال: critical section



iamehsan56
سه شنبه 22 بهمن 1392, 19:02 عصر
تو برنامه ای که دارم می نویسم هر ترد اطلاعات یه ip رو می گیره که 100 تا مثلا پارامتر دریافت می کنه . من یه آرایه ای از رکورد درست کردم .
هر ترد باید یه بخش از ارایه رو که مربوط به خودشه اپدیت کنه . نمی دونم چطوری می تونم به ارایه از هر ترد دسترسی داشت . از طرفی فرم اصلی هم به اطلاعات این ارایه احتیاج داره و بهش دسترسی باید داشته باشه .


mySite:array[1..Max_site_Num] of TSite ;



type
TSite = record
SiteIP: string;

ParamValue: array[1..130] of string;


end;


من تو پست زیر راجع به criticalsection خوندم
http://barnamenevis.org/showthread.php?438435-VirtualTreeView

اما یه چیزی رو متوجه نشدم . متغیز از نوع tcriticalsection رو باید کجا تعریفش کر ؟ تو فرم اصلی یا داخل ترد ؟
یعنی به شکل عمومی توفرم اصلی ، یا عمومی تو ترد
من یه جایی دیدم به شکل یه پارامتر از طریق کانستراکتور ترد پاسش دادن


t:=My.Create(true,mycritical)

می شه اون نمونه کدی که گذاشته شده ، بخش تعریفش رو هم تو فرم اصلی وترد بذارید و یه توضیح کوچیک هم بدید
کد زیر مربوط به همون پسته


const
WM_OutputReady = WM_USER +1;

StrListCriticalSection.Enter;
MemoStrList.Add('Some Texts');
StrListCriticalSection.Leave;
PostMessage(MainForm.Handle,WM_OutputReady,0,0);




procedure OnOutputReady(var Msg: Tmessage); message WM_OutputReady;
.
.
.
procedure TMainForm.OnOutputReady(var Msg: Tmessage);
begin
if MemoStrList.Count>0 then
begin
StrListCriticalSection.Enter;
Memo1.Lines.AddStrings(MemoStrList)
MemoStrList.Clear;
StrListCriticalSection.Leave;
end;
end;

ممنون می شم راهنمایی بفرمایید اساتید محترم

BORHAN TEC
سه شنبه 22 بهمن 1392, 19:27 عصر
سلام

اما یه چیزی رو متوجه نشدم . متغیز از نوع tcriticalsection رو باید کجا تعریفش کر ؟ تو فرم اصلی یا داخل ترد ؟
این متغیر باید به صورت global باشه، یعنی جایی که از تمامی تردها بشه به اون دسترسی داشت.
بهترین مثالی که در این مورد در رابطه با دلفی وجود داره مقاله Delphi threading by example هست که در edn وجود داره که برای خواندن این مقاله می توانید به لینک زیر مراجعه کنید:
http://edn.embarcadero.com/article/22411
توجه: برای دسترسی به لینک بالا باید از روشهای غیر رایج استفاده کنید.
موفق باشید...

iamehsan56
چهارشنبه 23 بهمن 1392, 07:27 صبح
ممنون
اما خیلی دقیق متوجه نشدم
ممکنه خیلی ساده تو همون کدی که بالا گذاشتم بگید که تعریف criticalsection باید چطور باشه و این که من یه جایی دیدم به شکل یه پارامتر از طریق کانستراکتور ترد پاسش دادن


t:=My.Create(true,mycritical)

Mask
چهارشنبه 23 بهمن 1392, 10:42 صبح
اگر بخواهیم به طور ساده در این مورد صحبت کنیم :
در برنامه های multi-threaded applications گاهی اوقات اتفاق می افتد که در آن شما نیاز دارید که دو روال همزمان بتوانند دسترسی مشترک به منابعی داشته باشند مانند نوشتن در یک فایل . که در مواقع نادر هیچ مشکلی پیش نیامده و برنامه به روند کار خود ادامه میدهد ،اما در اغلب موارد دسترسی همزمان روالها به منابع ممکن است اثرات جبران ناپزیری را به همراه داشته باشد. مثلا کل دیتا از بین رفته و یا فایل آسیب دیده و خراب شود.
یکی از روشهایی که برای جلوگیری از بروز چنین مشکلاتی پیشنهاد میشود استفاده از Critical Sections ها میباشد.
این متد به طور کلی عملیات synchronization داخلی ایجاد کرده و روالهایی که در حال استفاده از یک منبع مشترک را داشته باشند ، وادار به عقب نشینی و ترتیب اجرا میکند . در این روش منبع اطلاعاتی مورد نظر ما تا زمانی که در حال پاسخگویی به یک روال باشد، کلیه درخواستهای رسیده را نگه داشته تا عملیات کاری بر روی منبع مشترک تمام شده و سپس به درخواست بعدی رسیدگی میکند.
البته دقت در استفاده از این متد واقعا ضروری میباشد، اگر مقدار زمان رسیدگی به یک روال بیش از حد مجاز باشد، برنامه به حالت بحرانی رسیده و موقتا کلیه امور را متوقف تا بتواند هر چه سریعتر به صف ایجاد شده رسیدگی کند.
نکته مهم : برای پیاده سازی CriticalSection از دو روش میتوان بهره برد :
1- استفاده از TRTLCriticalSection که از یونیتwindows.pas استفاده شده و API های ویندوز به کمکمان میآیند.
2- استفاده از TCriticalSection پیاده سازی شده توسط خود دلفی که در یونیت SyncObjs.pas موجود میباشد، که البته در این روش هم در آخر از API ها استفاده شده، اما با پیچیدگی کمتر. که البته در کارهای پیچیده و پیاده سازی دقیقتر با TimeOut ضریفتر استفاده مستقیم از API ها پیشنهاد میشه.
برای پیاده سازی این عملیات کافیست متغیری از این نوع در var اصلی فرم تعریف شود :

CritSect : TCriticalSection;
سپس در روال ساخته شده با استفاده از دستور

EnterCriticalSection(CritSect);
روالهای درخواست کننده را در حالت صبر و تحمل برده و سپس بعد از انجام عملیات بر روی منابع مورد نیاز با دستور زیر برنامه را به دریافت روالهای بعدی سوق میدهیم.

LeaveCriticalSection(CritSect);
برای نمونه در روال زیر ، میخواهیم عملیات نوشتن بر روی یک فایل را با استفاده از این متد پیاده سازی کنیم :

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, SyncObjs, IdContext, IdBaseComponent, IdComponent, IdCustomTCPServer,
IdTCPServer;

type
TForm1 = class(TForm)
IdTCPServer1: TIdTCPServer;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure IdTCPServer1Execute(AContext: TIdContext);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
CS: TCriticalSection;

implementation

{$R *.dfm}

procedure InitService;
begin
CS := TCriticalSection.create;
end;

procedure DestroyService;
begin
CS.free;
end;

procedure Writelog(value: string);
var
f: textFile;
s: string;
begin
CS.Enter;
s := value;
s := extractfilepath(ParamStr(0)) + 'access.log';
assignfile(f, s);
if fileexists(s) then
append(f)
else
rewrite(f);
try
writeln(f, value);
finally
Closefile(f);
CS.Leave;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
InitService;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
DestroyService;
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
begin
Writelog(AContext.Connection.IOHandler.ReadLn());
end;

end.
خواندن منابع زیر به شدت توصیه میشود :
http://www.delphicorner.f9.co.uk/articles/op4.htm
http://thaddy.co.uk/threads/Ch6.html

البته کلیه مطالب بالاترجمه شخصی و برداشت من از آموزشهای موجود بود . اگر در هر قسمتی ، اشتباهی در توضیح وجود داشت ، خوشحال میشوم دوستان تذکر داده و رفع اشکال شود.
موفق باشید.