PDA

View Full Version : سوال: دستور MyThread.Abort() کار نمی کند. چرا؟



mj_developer
یک شنبه 10 بهمن 1389, 23:53 عصر
کد من بصورت زیر هست:


private void btnStop_Click(object sender, EventArgs e)
{
if (t.ThreadState == ThreadState.Running)
{
t.Abort();
}
}

وقتی روی دکمه btnStop کلیک می کنم Thread مورد نظر (t) از بین نمی رود و به کار خود ادامه می دهد. باید چیکار کنم؟


مرسی

AmirHarirbafan
دوشنبه 11 بهمن 1389, 01:23 صبح
چون دستور Abort رو خارج از Thread فراخوانی کردید ، تضمینی وجود ندارد که نخ متوقف بشه. این دستور فقط از داخل نخ تضمین میکنه که نخ رو متوقف کنه.
بهترین روش برای خارج کردن از یک نخ اینه که یک متغییر سراسری در نظر بگیرید و داخل نختون چکش کنید.(در داخل نخ باید دستور شرطی بزارید و t.Abort رو فراخوانی کنید.

AmirHarirbafan
دوشنبه 11 بهمن 1389, 01:24 صبح
یک نکته اضافه تر اینکه همیشه قبل از خروج از برنامه باید همه ی نخ ها متوقف شده باشن وگرنه ممکن است تمام فرم ها بسته شده باشن اما برنامه در پس زمینه هنوز در حال اجرا باشه

موفق باشید

haghft
دوشنبه 11 بهمن 1389, 10:18 صبح
از دستور thread.join(); استفاده کن خیلی وقتها من امتحان کردم این کد جواب داده.

mj_developer
دوشنبه 11 بهمن 1389, 15:23 عصر
چون دستور Abort رو خارج از Thread فراخوانی کردید ، تضمینی وجود ندارد که نخ متوقف بشه. این دستور فقط از داخل نخ تضمین میکنه که نخ رو متوقف کنه.
بهترین روش برای خارج کردن از یک نخ اینه که یک متغییر سراسری در نظر بگیرید و داخل نختون چکش کنید.(در داخل نخ باید دستور شرطی بزارید و t.Abort رو فراخوانی کنید.

منظورتون رو از جمله زیر متوجه نمیشم:
بهترین روش برای خارج کردن از یک نخ اینه که یک متغییر سراسری در نظر بگیرید و داخل نختون چکش کنید.(در داخل نخ باید دستور شرطی بزارید و t.Abort رو فراخوانی کنید.

ali.rezaei7
دوشنبه 11 بهمن 1389, 18:19 عصر
درود. معمولا اين اتفاق زماني رخ ميده كه كه نخ بحالت Sleep رفته. در اين صورت، نمي شه تا وقتي كه نخ از حالت Sleep خارج نشده، نخ رو Abort كرد! چند راه وجود داره يكي استفاده از متغير عمومي است كه دوستمون هم گفتن. يكي استفاده از كلاس System.Timers.Timer هست(در صورتي كه مي خواي كدها در يه دوره زماني ثابت اجرا بشه.) و براي از بين بردن نخ استفاده كردن از متد dispose.

و بلاخره استفاده از اين كد براي از بين بردن Thread:(اگه در حال Sleep باشه.)


t.Join(1);
t.Abort();

AmirHarirbafan
دوشنبه 11 بهمن 1389, 20:03 عصر
منظور از تعریف متغییر سراسری و چک کردن در داخل Thread رو در مثال زیر توضیح دادم



public class myThreadClass
{
private bool cancelThread = false;

private void MyThreadMethod()
{
while (true)
{
// Do something

if (cancelThread)
{
t.Abort();
}
// Do something
}
}

private void btnStop_Click(object sender, EventArgs e)
{
if (t.ThreadState == ThreadState.Running)
{
cancelThread = true;
}
}
}

mj_developer
دوشنبه 11 بهمن 1389, 22:29 عصر
منظور از تعریف متغییر سراسری و چک کردن در داخل Thread رو در مثال زیر توضیح دادم



public class myThreadClass
{
private bool cancelThread = false;

private void MyThreadMethod()
{
while (true)
{
// Do something

if (cancelThread)
{
t.Abort();
}
// Do something
}
}

private void btnStop_Click(object sender, EventArgs e)
{
if (t.ThreadState == ThreadState.Running)
{
cancelThread = true;
}
}
}

من با اینکه مقدار متغیر cancelThread رو در روال btnStop برابر با true می کنم باز هم در روال مربوط به Thread مقدار اون برابر false هست. باید چیکار کنم؟

AmirHarirbafan
دوشنبه 11 بهمن 1389, 22:37 عصر
توی این برنامه سه روش متوقف کردن یک Thread رو توضیح دادم.

65794

موفق باشید

amir001
سه شنبه 12 بهمن 1389, 00:20 صبح
باید بعد از Abort() یک بار هم Join() را فراخوانی کنی.

من کلا برای اینکه مطمئن بشم نخ ها بسته شدن این کار را میکنم


Temp.Interrupt();
Temp.Abort();
Temp.Join();

mehdi.mousavi
سه شنبه 12 بهمن 1389, 00:40 صبح
سلام.
بچه ها این چه روشهایی هستش که به هم پیشنهاد میدید؟


استفاده از متود Abort فقط باید تحت شرایط Critical باشه، و لا غیر. این متود منجر به فراخوانی TerminateThread Win32 API میشه و این API نیز فقط باید در شرایط بحرانی فراخوانی بشه. (منظور از شرایط بحرانی چیه؟ منظور شرایطی هستش که شما به Thread ای T واحد زمانی فرصت میدید تا متوقف بشه. اگر نشد، مجبورید بعنوان Safe Guard اون Thread رو متوقف کنید. در چنین شرایطی، اگر Thread شما Handle به یک Kernel Object داشته باشه، احتمال اینکه اون Handle آزاد نشه و در کارکرد Driver خللی پیش بیاد، بسیار بسیار زیاده؛ بنابراین هنگام طراحی Driver ها باید حتی الامکان به این مسائل نیز فکر کرد). بدتر از اون، استفاده از Abort داخل خود Thread Function هستش. این کار برای چی هستش؟ که دستی دستی Exception تولید کنید؟؟؟ میدونید تولید یک Exception چقدر هزینه بر هستش؟
استفاده از Boolean Variable ها برای بررسی خاتمه دادن یا ندادن به فعالیت یک Thread، اونم داخل یک Loop، میتونه باعث به زانو در اومدن CPU و در نتیجه کل ماشین بشه. ضمن اینکه این متغیرها برای دسترسی همزمان در سطح Kernel برنامه ریزی نشده اند، در نتیجه، بسته به نوع استفاده، میتونه نتایج عجیب و غریب دیگه ای رو در پی داشته باشه.

روش درست، استفاده از متود Join هستش، اما Join فقط انتظار میکشه تا دو Thread به همدیگه بپیوندن، به بیان دیگه، Worker Thread شما هر وقت کارش تموم بشه، اونوقت متود Join (در Main Thread) خارج میشه و اجرای برنامه در Main Thread، ادامه پیدا میکنه. اما سوال این هستش که چطوری در Worker Thread امون متوجه بشیم که وقت خارج شدن از Thread فرا رسیده؟ اگر قراره از Boolean استفاده نکنیم، پس از چی استفاده کنیم؟ ما Object هایی در سطح Kernel داریم که برای همزمانی دو یا چند Thread ایجاد شده اند. به این Object ها Synchronization Object میگن. یکی از این Object ها، Event ها هستن. کلاس ManualResetEvent نیز یکی از کلاسهایی هستش که Event Synchronization رو پیاده سازی کرده:



ManualResetEvent existThread = new ManualResetEvent(false);

private void MyThreadMethod()
{
while (!existThread.WaitOne(100))
{
//Do something
}
}


private void buttonExitMyThread_Click(object sender, EventArgs e)
{
existThread.Set();
t.Join();
}


در کد فوق، من یک ManualResetEvent تعریف میکنم و اونو در حالت false یا reset قرار میدم. هر Event ای دو حالت داره، یا Set هستش، یا Reset. اون پارامتری که هنگام ایجاد اون کلاس پاس کردم بهش نشون میده که وضعیت ابتدایی این Synchronization Object چی هست. سپس، در Worker Thread ام، در Loop اصلی، بررسی میکنم که آیا اون Event سیگنال شده یا خیر (یعنی Set شده یا نه و برای اینکار، 100 میلی ثانیه نیز زمان در نظر گرفته ام). اگر Signal شده باشه، متوجه میشم که یه Thread دیگه ای اونو Set کرده، پس باید به کار Thread خاتمه بدم. پس حلقه رو رها میکنم و از تابع مربوطه خارج میشم...

سپس در Main Thread، وقتی که کلید ExitMyThread زده میشه، ابتدا اون Event رو Signal میکنم و سپس، به Worker Thread فرصت میدم تا کار نهاییش رو انجام بده و خارج بشه (برای همین هستش که خط بعد Signal کردن Event، از Join استفاده کرده ام، چون باید کنترل کنم که تا وقتی Worker Thread ام حقیقتا پایان نپذیرفته، نذارم Main Thread ام به کارش ادامه بده).

استفاده از این روش، خوبیهایی داره:


اول اینکه Handle به Event ها در سزح کرنل گرفته شده اند و Thread Safe هستن. بنابراین Race Condition پیش نمیاد و همزمانی Thread ها بر اساس برنامه ریزی انجام میشه.
عمل هزینه بر Throw کردن Exception رخ نمیده.
CPU Usage به 100% نمیرسه.

موفق باشید.

AmirHarirbafan
سه شنبه 12 بهمن 1389, 03:04 صبح
سلام.
بچه ها این چه روشهایی هستش که به هم پیشنهاد میدید؟


استفاده از متود Abort فقط باید تحت شرایط Critical باشه، و لا غیر. این متود منجر به فراخوانی TerminateThread Win32 API میشه و این API نیز فقط باید در شرایط بحرانی فراخوانی بشه. (منظور از شرایط بحرانی چیه؟ منظور شرایطی هستش که شما به Thread ای T واحد زمانی فرصت میدید تا متوقف بشه. اگر نشد، مجبورید بعنوان Safe Guard اون Thread رو متوقف کنید. در چنین شرایطی، اگر Thread شما Handle به یک Kernel Object داشته باشه، احتمال اینکه اون Handle آزاد نشه و در کارکرد Driver خللی پیش بیاد، بسیار بسیار زیاده؛ بنابراین هنگام طراحی Driver ها باید حتی الامکان به این مسائل نیز فکر کرد). بدتر از اون، استفاده از Abort داخل خود Thread Function هستش. این کار برای چی هستش؟ که دستی دستی Exception تولید کنید؟؟؟ میدونید تولید یک Exception چقدر هزینه بر هستش؟
استفاده از Boolean Variable ها برای بررسی خاتمه دادن یا ندادن به فعالیت یک Thread، اونم داخل یک Loop، میتونه باعث به زانو در اومدن CPU و در نتیجه کل ماشین بشه. ضمن اینکه این متغیرها برای دسترسی همزمان در سطح Kernel برنامه ریزی نشده اند، در نتیجه، بسته به نوع استفاده، میتونه نتایج عجیب و غریب دیگه ای رو در پی داشته باشه.

روش درست، استفاده از متود Join هستش، اما Join فقط انتظار میکشه تا دو Thread به همدیگه بپیوندن، به بیان دیگه، Worker Thread شما هر وقت کارش تموم بشه، اونوقت متود Join (در Main Thread) خارج میشه و اجرای برنامه در Main Thread، ادامه پیدا میکنه. اما سوال این هستش که چطوری در Worker Thread امون متوجه بشیم که وقت خارج شدن از Thread فرا رسیده؟ اگر قراره از Boolean استفاده نکنیم، پس از چی استفاده کنیم؟ ما Object هایی در سطح Kernel داریم که برای همزمانی دو یا چند Thread ایجاد شده اند. به این Object ها Synchronization Object میگن. یکی از این Object ها، Event ها هستن. کلاس ManualResetEvent نیز یکی از کلاسهایی هستش که Event Synchronization رو پیاده سازی کرده:



ManualResetEvent existThread = new ManualResetEvent(false);

private void MyThreadMethod()
{
while (!existThread.WaitOne(100))
{
//Do something
}
}


private void buttonExitMyThread_Click(object sender, EventArgs e)
{
existThread.Set();
t.Join();
}
در کد فوق، من یک ManualResetEvent تعریف میکنم و اونو در حالت false یا reset قرار میدم. هر Event ای دو حالت داره، یا Set هستش، یا Reset. اون پارامتری که هنگام ایجاد اون کلاس پاس کردم بهش نشون میده که وضعیت ابتدایی این Synchronization Object چی هست. سپس، در Worker Thread ام، در Loop اصلی، بررسی میکنم که آیا اون Event سیگنال شده یا خیر (یعنی Set شده یا نه و برای اینکار، 100 میلی ثانیه نیز زمان در نظر گرفته ام). اگر Signal شده باشه، متوجه میشم که یه Thread دیگه ای اونو Set کرده، پس باید به کار Thread خاتمه بدم. پس حلقه رو رها میکنم و از تابع مربوطه خارج میشم...

سپس در Main Thread، وقتی که کلید ExitMyThread زده میشه، ابتدا اون Event رو Signal میکنم و سپس، به Worker Thread فرصت میدم تا کار نهاییش رو انجام بده و خارج بشه (برای همین هستش که خط بعد Signal کردن Event، از Join استفاده کرده ام، چون باید کنترل کنم که تا وقتی Worker Thread ام حقیقتا پایان نپذیرفته، نذارم Main Thread ام به کارش ادامه بده).

استفاده از این روش، خوبیهایی داره:


اول اینکه Handle به Event ها در سزح کرنل گرفته شده اند و Thread Safe هستن. بنابراین Race Condition پیش نمیاد و همزمانی Thread ها بر اساس برنامه ریزی انجام میشه.
عمل هزینه بر Throw کردن Exception رخ نمیده.
CPU Usage به 100% نمیرسه.

موفق باشید.


اما در msdn گفته که برای خارج کردن یک Thread در شرایطی که در Thread به یک وقفه سیستمی دسترسی پیدا نمیکنید، از متغییر و دستور join باید استفاده کرد.
http://msdn.microsoft.com/en-us/library/7a2f3ay4(v=vs.80).aspx (http://msdn.microsoft.com/en-us/library/7a2f3ay4%28v=vs.80%29.aspx)

برای مواردی که یکی از وقفه های سیستمی رو فراخوانی میکنیم، من یه جا خوندم بهتر از یک Process جدا استفاده کرد، که البته من موافق نیستم چون بسیار هزینه بر هستش و فکر کنم روشی رو که شما در بالا مطرح کردید بهتر باشه.

سوالی که برام پیش اومده اینه که میشه یک نخ که دارای دستوری هست که اونو کاملا مسدود میکنه رو متوقف کرد



private void MyThreadMethod()
{
// kari ke baese masdud shodan thread be surat bi nahayat shavad
new Form1().ShowDialog();
}

mehdi.mousavi
سه شنبه 12 بهمن 1389, 10:46 صبح
اما در msdn گفته که برای خارج کردن یک Thread در شرایطی که در Thread به یک وقفه سیستمی دسترسی پیدا نمیکنید، از متغییر و دستور join باید استفاده کرد.
http://msdn.microsoft.com/en-us/library/7a2f3ay4(v=vs.80).aspx (http://msdn.microsoft.com/en-us/library/7a2f3ay4%28v=vs.80%29.aspx)

برای مواردی که یکی از وقفه های سیستمی رو فراخوانی میکنیم، من یه جا خوندم بهتر از یک Process جدا استفاده کرد، که البته من موافق نیستم چون بسیار هزینه بر هستش و فکر کنم روشی رو که شما در بالا مطرح کردید بهتر باشه.

سوالی که برام پیش اومده اینه که میشه یک نخ که دارای دستوری هست که اونو کاملا مسدود میکنه رو متوقف کرد



private void MyThreadMethod()
{
// kari ke baese masdud shodan thread be surat bi nahayat shavad
new Form1().ShowDialog();
}



سلام.
MSDN کم ایراد نداره... استفاده از متغیر bool اصلا کار مناسبی برای همزمانی دو Thread نیست، حتی اگر متغیر مربوطه volatile تعریف شده باشه... در هر حال، به مطالبی که گفتم 100% اطمینان دارم، بنابراین نگران نباشید. :) اما در مورد مساله دومی که مطرح کردید، یعنی Block شدن یک Thread... واقعیت اینه که ما باید کنترل Thread هامون رو برنامه ریزی شده در اختیار بگیریم و هرگز نذاریم چنین شرایطی پیش بیاد. اما اگر چنین شرایطی پیش اومد، میتونیم از Abort استفاده کنیم. Abort باعث توقف Thread میشه، اما هیچ فرصتی به Thread برای عملیات Cleanup نمیده، در نتیجه ممکنه بسیاری از Resource های سیستمی آزاد نشن و Sub-System ها در وضعیت ناشناخته رها بشن. من برای اینکه کدی که بالا نوشتم پیچیده نشه، دیگه برای Thread ام Timeout نذاشتم. و الا روش درست این هستش که Join رو با یک Timeout ای Call کنم، Timeout ای که به Worker Thread ام اجازه بده کارش تموم بشه. اگر اون Timeout توسط Worker Thread ام Meet نشد و کار Thread پایان نپذیرفت (به هر دلیلی)، اونوقت باید پس از Join از متود Abort برای متوقف کردن Worker Thread ام استفاده کنم. البته اینجا بازهم میتونم یه فرصت دوباره ای به Thread ام بدم که کارش رو تموم کنه، اما اگر بازهم در timeout مورد نظرم این اتفاق نیفتاد، اونوقت مجبورم که Thread رو abort کنم...

موفق باشید.