PDA

View Full Version : مشکل در ارتباط بین دو Thread



Reza_Yarahmadi
سه شنبه 19 خرداد 1388, 11:51 صبح
سلام
قبل از هر چیزی بخاطر عنوان نه چندان جالب ببخشید هر چی فکر کردم واسه مشکلم چه عنوانی بذارم ...!!
توی برنامه ام قراره یک سری کارهای وقت گیر انجام بشه (زمان اجرای کل تقریبا 4 دقیقه میشه) . برای جلوگیری از به حالت هنگ رفتن برنامه همه کارها رو توی یه نخ دیگه انجام میدم. زمانی هم که اون نخ رو استارت میزنم یه فرم لودینگ ظاهر میشه. تا اینجای کار هیچ مشکلی نیست ، مشکل من اینه که میخوام وقتی کار این نخ تموم شد صفحه لودینگ هم بسته بشه. برای این کار بصورت زیر عمل کردم:
اول یه نخ درست کردم و اونو استارت زدم در همون حین فرم لودینگ رو هم نمایش میدم


private void btnStart_Click(object sender, EventArgs e)
{
ManagerThread = new Thread(new ThreadStart(CreatePrimalPopulation));
LoadingForm.Show();
ManagerThread.Start();
}

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


void CreatePrimalPopulation()
{
...
...
...
LoadingForm.Close();
}


ولی نمیدونم چرا زمانی که به خط بسته شدن فرم لودینگ میرسه خطا میگیره(Exception) متن این خطا هم اینه
Cross-thread operation not valid: Control 'Loading' accessed from a thread other than the thread it was created on.

حالا به نظر شما چطور باید این مشکل رو برطرف کرد؟

mohsen_csharp
سه شنبه 19 خرداد 1388, 12:37 عصر
قبلش این کد رو بنویس ببین درست میشه؟

Control.CheckForIllegalCrossThreadCalls = false;

Saeed_m_Farid
سه شنبه 19 خرداد 1388, 14:35 عصر
قبلش این کد رو بنویس ببین درست میشه؟

Control.CheckForIllegalCrossThreadCalls = false;
شما داری روی صورت مساله رو پاک می کنی.
دلیل این که شما این خطا رو دریافت می کنید، اینه که شما از Thread فرزند دارین به ایجاد کننده اون access می کنید و می بندینش.
به نظر من بهتره اینکار از طریق ارسال پیام به LoadingForm تون انجام بشه، برای اینکار باید بعد اتمام کارتون تو Thread موردنظر Stop اش کنید و یه پیغام برای LoadingForm بفرستین که خودش رو ببنده، برای قسمت دوم هم (یعنی دریافت پیام توسط LoadingForm) باید Windows procedure رو override کنید، مثلاً اینطوری :

protected override void WndProc(ref Message mess ){
// Listen for operating system messages.
switch( mess.Msg ) {
case WM_CLOSE_LOADINGFORM: {
// کارهایی که میخواهید انجام بدین
LoadingForm.Close(); // or this.Close();
break;
}

base.WndProc(ref mess);
}
}
البته این ثابت WM_CLOSE_LOADINGFORM رو هم باید تعریف کنید و از طریق همون پیام به فرمتون دستور بسته شدن بدید :

// اول برنامه
private const int WM_CLOSE_LOADINGFORM = 0x4FF0;

// برای ارسال پیام
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int PostMessage(HandleRef hwnd, int msg, IntPtr wparam, IntPtr lparam);

pesar irooni
سه شنبه 19 خرداد 1388, 14:53 عصر
چون اون فرم که لودکردی خودش تو یه نخ دیگه داره اجرا میشه و شما میخوای از یه نخ که داره همزمان با اون اجرا میشه محتویات نخ دیگه رو دستکاری کنی و این اجازه در حالت پیش فرض به شما داده نمیشه.
میتونی به جز کاری که دوستمون گفت دو کار انجام بدی. یکی اینکه تو یه حلقه با بازه زمانی مثلا 1 ثانیه چک کنی ببینی نخ هنوز داره کار میکنه (با متد IsAlive یا همین چیزی از خود نخ) و یا یه چیزی شبیه InvokeRequired برای فرم پیدا کنی. مثلا من میخواستم داخل یه نخ یکی از کنرلهای فرمم رو تغییر بدم همون خطای شما رو میداد و من مثل این کد رو نوشتم :

public void SetStatus( string text )
{
if (LoadingForm.InvokeRequired)
{
this.Label_Status.BeginInvoke(
new MethodInvoker(
delegate() { SetStatus( text ); } ) );
}
else
{
this.Label_Status.Text = text;
}
}

prankster
سه شنبه 19 خرداد 1388, 22:25 عصر
ساده ترین راه در کار بر روی کنترل های windows در Thread های جداگانه این است که اجرای دستورات را به thread ی که کنترل را ایجاد کرده است برگردانید
در مثال شما:


this.Invoke(new MethodInvoker(delegate()
{
LoadingForm.Close();
}));


اگر خواستید بگویید توضیح می دهم

hamid67fathi
چهارشنبه 20 خرداد 1388, 00:25 صبح
ممنون ميشم اگه بيشتر توضيح بديد !!
من همين مشکل رو با BackGroundWorker دارم !

dr_jacky_2005
شنبه 01 آبان 1389, 16:02 عصر
من یک فرم لودینگ دارم که تووش پروگرس بار است.
یک فرم هم دارم که تووش درخت است و با تابعی پر از دیتا میشود.
اینگونه عمل کرده ام:
این رو نوشتم توو فرم که درخت تووشه که بتونم فرم لودینگ رو شو کنم:

LoadingForm frmp;

اینم توو لود فرمه که تووش درخته:

frmp = new LoadingForm();
frmp.Show();
this.Cursor = Cursors.WaitCursor;
backgroundWorker1.RunWorkerAsync();

اینم توو دوو ورک بکگرادنورکر:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int returnedRecordCount = 100;
for (int i = 1; i <= returnedRecordCount; i++)
{
if (this.backgroundWorker1.CancellationPending)
{
e.Cancel = true;
return;
}
this.backgroundWorker1.ReportProgress(i);

System.Threading.Thread.Sleep(20);
}
if (TrvCoding.InvokeRequired)
{

TrvCoding.Invoke(new MethodInvoker(delegate { TvfCoding.LoadTreeFullDate(); }));

//TvfCoding.LoadTreeFullDate();
}
}

اینم توو کامپلیت:

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Cursor = Cursors.Default;
frmp.Close();
//frmp.Hide();
}

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

private void HesabStateWorkForm_FormClosed(object sender, FormClosedEventArgs e)
{
if (this.backgroundWorker1.IsBusy) this.backgroundWorker1.CancelAsync();
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage <= this.frmp.progressBar1.Maximum)
{
this.frmp.progressBar1.Value = e.ProgressPercentage;
}
}

اینم توو لود فرم لودینگ:

progressBar1.Value = 0;
for (int x = 0; x < 100; x++)
{
if (progressBar1.Value < progressBar1.Maximum)
{
//System.Threading.Thread.Sleep(10);
progressBar1.Value++;
}
}

اینا هم نکته ها:
دو تا پروپرتی توانایی کنسل کردن و گزارش دادن true است.
و
فرم لودینگ هم TopMost = true

سوالات:
الآن همه چی میاد،عالی...
ولی
اول لودینگ میاد،بعد پر شدن درخت شروع میشه!

من میخوام هم زمان باشن!


دومین چیزی که میخوام اینه که پر شدن لودینگ متناسب باشه به مقداری که لازمه.

اگر مورد بالا نشد،میخوام که پروگرس بار بلوکی نباشد،marquee باشد.(style)

tooraj_azizi_1035
یک شنبه 02 آبان 1389, 10:25 صبح
سلام، این لینک: http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx

dr_jacky_2005
یک شنبه 02 آبان 1389, 13:04 عصر
سلام، این لینک: http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx (http://msdn.microsoft.com/en-us/library/ms171728%28VS.80%29.aspx)

مرسی ولی چیز خاصی واسه حل شدن مشکل من نداش!

mahdi87_gh
یک شنبه 02 آبان 1389, 13:17 عصر
دوست عزیز در فرم لودینگ بجای قرار دادن یه حلقه for الکی، از یه عکس gif استفاده کنید.
دز موقع شروع بکار backgroundWorker فرم لودینگ رو نمایش داده و در موقع پایان کار backgroundWorker فرم لودینگ رو ببندید. اگر مشکل برخوردید، اطلاع بدین تا یه نمونه قرار بدم

dr_jacky_2005
یک شنبه 02 آبان 1389, 14:18 عصر
دوست عزیز در فرم لودینگ بجای قرار دادن یه حلقه for الکی، از یه عکس gif استفاده کنید.
دز موقع شروع بکار backgroundWorker فرم لودینگ رو نمایش داده و در موقع پایان کار backgroundWorker فرم لودینگ رو ببندید. اگر مشکل برخوردید، اطلاع بدین تا یه نمونه قرار بدم

اگه این تغییری که شما گفتینو بکنم...1 ثانیه لوینگ میاد،میره،فرمی که درخت تووشه،رو میشه تکوون داد.

اگه لطف کنید یک نمونه بزارین ممنون میشم.

البته مثالی که میزنید لطفا طوری باشه که 100% تابع پر کردن درختم توو این تیکه باشه:

if (TrvCoding.InvokeRequired)
{

TrvCoding.Invoke(new MethodInvoker(delegate { TvfCoding.LoadTreeFullDate(); }));

//TvfCoding.LoadTreeFullDate();
}

mahdi87_gh
یک شنبه 02 آبان 1389, 14:48 عصر
دوست عزیز من با backgroundWorker انجام دادم اما یه اروری داشت که دیگه حال نداشتم بگردم درستش کنم. از یه روش دیگه که قبلا اسنفاده کرده بودم یه مثال میزارم نگاه کن

dr_jacky_2005
یک شنبه 02 آبان 1389, 15:17 عصر
دوست عزیز من با backgroundWorker انجام دادم اما یه اروری داشت که دیگه حال نداشتم بگردم درستش کنم. از یه روش دیگه که قبلا اسنفاده کرده بودم یه مثال میزارم نگاه کن


ممنون ولی این مشکل من نیس!!!!!!

اصلا شما از backgroundworker استفاده نکردین!!!!!

این کاری که شما گفتین رو میکنم...یه در میون ترد ها اجرا میشه.
یعنی میاد مرحله اول از فرم لودینگ یک نمونه میگیره.
مرحله بعد : تابع پر کردن رو اجرا میکنه.
مرحله بعد میخواد فرم لودینگی که یک نمونه ازش کگرفته بوود رو نشون بده که دیگه نوبتش نمیشه و ترد استاپ میشه.

اصلا این روش ترد دستی رو نمیخوام
Just backGroundWorker

dr_jacky_2005
دوشنبه 03 آبان 1389, 08:50 صبح
من یک فرم لودینگ دارم که تووش پروگرس بار است.
یک فرم هم دارم که تووش درخت است و با تابعی پر از دیتا میشود.
اینگونه عمل کرده ام:
این رو نوشتم توو فرم که درخت تووشه که بتونم فرم لودینگ رو شو کنم:

LoadingForm frmp;اینم توو لود فرمه که تووش درخته:

frmp = new LoadingForm();
frmp.Show();
this.Cursor = Cursors.WaitCursor;
backgroundWorker1.RunWorkerAsync();اینم توو دوو ورک بکگرادنورکر:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int returnedRecordCount = 100;
for (int i = 1; i <= returnedRecordCount; i++)
{
if (this.backgroundWorker1.CancellationPending)
{
e.Cancel = true;
return;
}
this.backgroundWorker1.ReportProgress(i);

System.Threading.Thread.Sleep(20);
}
if (TrvCoding.InvokeRequired)
{

TrvCoding.Invoke(new MethodInvoker(delegate { TvfCoding.LoadTreeFullDate(); }));

//TvfCoding.LoadTreeFullDate();
}
}اینم توو کامپلیت:

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Cursor = Cursors.Default;
frmp.Close();
//frmp.Hide();
}اینم وقتی که فرمه که تووش درخته،دارخ بسته میشه:

private void HesabStateWorkForm_FormClosed(object sender, FormClosedEventArgs e)
{
if (this.backgroundWorker1.IsBusy) this.backgroundWorker1.CancelAsync();
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage <= this.frmp.progressBar1.Maximum)
{
this.frmp.progressBar1.Value = e.ProgressPercentage;
}
}اینم توو لود فرم لودینگ:

progressBar1.Value = 0;
for (int x = 0; x < 100; x++)
{
if (progressBar1.Value < progressBar1.Maximum)
{
//System.Threading.Thread.Sleep(10);
progressBar1.Value++;
}
}اینا هم نکته ها:
دو تا پروپرتی توانایی کنسل کردن و گزارش دادن true است.
و
فرم لودینگ هم TopMost = true

سوالات:
الآن همه چی میاد،عالی...
ولی
اول لودینگ میاد،بعد پر شدن درخت شروع میشه!

من میخوام هم زمان باشن!


دومین چیزی که میخوام اینه که پر شدن لودینگ متناسب باشه به مقداری که لازمه.

اگر مورد بالا نشد،میخوام که پروگرس بار بلوکی نباشد،marquee باشد.(style)

کسی نیست کمک کنه؟