PDA

View Full Version : background worker



HAIdle
سه شنبه 15 خرداد 1386, 19:09 عصر
من به backgroundworker مشکل زیر را دارم:

توی رویداد BackgroundWorker1.DoWork به یک combobox دسترسی پیدا می کنم که خطای زیر را می ده:

Cross-thread operation not valid: Control 'vilageComboBox' accessed from a thread other than the thread it was created on

چه کنم؟

kiani.mehdi
سه شنبه 15 خرداد 1386, 21:45 عصر
کد زیر را تو رویداد لود فرم اصلیت یا توی constructor فرم اصلیت بعد از initializeComponent() بذار




Control.CheckForIllegalCrossThreadCalls = false;


موفق باشید
مهدی کیانی

HAIdle
چهارشنبه 16 خرداد 1386, 12:22 عصر
یه مشکل جدید:
می خواهیم مثلا وقتی دکمه ای کلیک شد رویداد backgroundworker.dowork از اول فراخوانی شود. اگر همین طور runworkerasync را اجرا کنیم که خطا می دهد چون می

گو ید در این نخ الان یک کار در حال انجام است. تا اینجا تعجبی ندارد ولی وقتی cancelasync را هم اجرا می کنیم باز وقتی به خط بعدی یعنی اجرای runworkerasync می رسد همان خطا

را می ده که نخ داره اجرا میشه. مگه ما cancel نکردیمش .

mehdi.mousavi
چهارشنبه 30 خرداد 1386, 18:17 عصر
من به backgroundworker مشکل زیر را دارم:

توی رویداد BackgroundWorker1.DoWork به یک combobox دسترسی پیدا می کنم که خطای زیر را می ده:

Cross-thread operation not valid: Control 'vilageComboBox' accessed from a thread other than the thread it was created on

چه کنم؟


سلام
یکی از دوستان پیشنهاد استفاده از CheckForIllegalCrossThreadCalls رو دادن، که من 100% باهاش مخالفم. راه درست این هستش که از متود ReportProgress استفاده کنید، به این ترتیب Event ای Fire میشه که در کانتکست Main Thread شما هستش و شما می تونید بدون نگرانی به کنترلهای صفحه دست پیدا کنید.

در مورد CancelAsync هم باید عرض کنم که اسم متود روشه! Asynchronous کار میکنه. یعنی اینکه خارج شدن از این متود به معنی Cancel شدن BW نیست، بلکه به معنی شروع عمل Cancel شدن هستش. این وظیفه شما هستش که با Synchronization Object ها از اتمام کار BW، بعد ازCancelAsync اطمینان پیدا کنید.

__H2__
پنج شنبه 31 خرداد 1386, 10:29 صبح
سلام
من هم با نظرات کاربر mehdi6755 (http://www.barnamenevis.org/forum/member.php?u=41233) موافق هستم!
برای ارسال مقادیر به شاخه، بهتر است قبل از شروع شاخه مقادیر را با کمک (RunWorkerAsync(Object argument ارسال کنید و در داخل رویداد مقادیر را از e.Argument تحویل بگیرید.

و برای فرستادن مقادیر از رشته به برنامه اصلی هم میتوانید از متد ReportProgress و رویداد ProgressChanged و یا e.Result استفاده کنید.

برای چک کردن وضعیت و شروع مجدد هم میتوانید از خصوصیات CancellationPending و IsBusy کمک بگیرید.
البته راه های دیگری هم دارد، ولی معمولاً با همین روشهای رسمی تر و قانونی تر مشکل برطرف میشود! و نیز این روشها پرسرعت هم هستند.

البته از کاربر kiani.mehdi هم تشکر میکنم، چون من اصلاً آن مشخصه را ندیده بودم!!!!!؟؟؟؟؟!!!! ولی به نظرم جالب نیست!

Alirezanet
یک شنبه 02 اسفند 1388, 13:55 عصر
سلام
اینجوری یه مقدار میشه از نوی Object فرستاد ...
من یه تابع توی برنامم دارم که میخواستم با استفاده از backgrondworler اجراش کنم و این تابع تودرتو هست که 3 تا مقدار متفاوت در هربار اجرا میگیره چجوری میشه اولا چند مقدار نوع از مقادیر رو ارسال کرد و مشکل تو در تو بودنشو حل کرد !؟

__H2__
شنبه 15 اسفند 1388, 19:36 عصر
سلام
از تاخیر جواب عضر خواهی میکنم.

چجوری میشه اولا چند مقدار نوع از مقادیر رو ارسال کرد
مساله مهمی نیست! کافی است آرایه کنید

مثلاً:


object one = new object[]{1,2,3};

//...


object[] arr = (object[])one;
object obj1 = arr[0];
object obj2 = arr[1];
object obj3 = arr[2];



مشکل تو در تو بودنشو حل کرد
درست متوجه نشدم؟
رویداد DoWork که آغاز شود میتوانید هر تابعی را فراخوانی کنید، مهم نیست، همه با ریسمان جدید انجام خواهد ...


public void DoWork(...)
{
Func1();
Func2();
Func3();
}

private Func1()
{
Func5();
Func6();
}

...


مجدد از تاخیر عضر خواهی میکنم و موفق باشید.

Alirezanet
شنبه 15 اسفند 1388, 22:30 عصر
:متفکر:ممنون از کمکتون اما اگه ما نخوایم که مقدار رو از نوع Obj ارسال کنیم چی ؟!!
یک مقدار این موضوع گنگه چون اگه همه مقادیر ارسالی رو بخوایم با تبدیل به این صورت ارسال کنیم کارایی و ... برنامه میاد پایین ... مثلا من میخوام یه String و یک TreeNode ارسال کنم ولی اونجوری نمیشه این کارو کرد ؟! اگه یک مقدار بیشتر توضیح بدین ممنون میشم ...
من مشکل همه رو توی این قضیه دارم توی تاپیک vb.net حل میکنم ولی خودم هنوز باهاش مشکل دارم !

Alirezanet
شنبه 15 اسفند 1388, 22:35 عصر
درست متوجه نشدم؟
رویداد DoWork که آغاز شود میتوانید هر تابعی را فراخوانی کنید، مهم نیست، همه با ریسمان جدید انجام خواهد ...


یه تابع هست که مثلا 2 مقدار میگیره و اجرا میشه و n دفعه خودش رو با 2 مقدار جدید راه اندازی میکنه(از توی کد های خودش .. مثله یه حلقه) ... DoWork یکبار اجرا میشه و نمیشه مثل همچین تابعی ازش استفاده کرد .... ؟

__H2__
یک شنبه 16 اسفند 1388, 00:01 صبح
سلام

... توی تاپیک vb.net ...
الآن کد VB میخواهید یا #c?


اما اگه ما نخوایم که مقدار رو از نوع Obj ارسال کنیم چی ؟!!
یک مقدار این موضوع گنگه چون اگه همه مقادیر ارسالی رو بخوایم با تبدیل به این صورت ارسال کنیم کارایی و ... برنامه میاد پایین ... مثلا من میخوام یه String و یک TreeNode ارسال کنم ولی اونجوری نمیشه این کارو کرد ؟! اگه یک مقدار بیشتر توضیح بدین ممنون میشم ...
این مسئله خیلی مهم و پیچیده ای نیست.
اولاً که شما راه های مختلفی دارید (که در پایین مثال میزنم)
بعد هم سرعت و بازدهی به سه دلیل عمده کاهش نمی یابد ...
1) فرمان قالب ریزی مستقیم سرعت بسیار زیادی دارد (DirectCast)
2) نصف این تبدیل فوق العاده سریع در ریسمان جدید انجام میشود که قرار است کار سنگینی انجام دهد ...
(مثل جمع عدد 1 با عدد 1000 می ماند که عملاً بی تاثیر است)

3) برنامه شما در حلقه کار نمیکند و این عمل فقط و فقط یکبار انجام میشود.
اصولاً هر کجا کاهش سرعت داریم، همانجا نوعی حلقه پیدا/پنهان داریم که کاری را مدام و مدام انجام میدهد.

روش اول:


//C#.Net
public void AsyncStart()
{
int param1 = 14;
string param2 = "14";
DateTime param3 = DateTime.UtcNow;

System.Threading.Thread thread = new System.Threading.Thread(this.Start);
thread.IsBackground = true;
thread.Start(new object[] { param1, param2, param3 });
}

private void Start(object obj)
{
object[] arr = (object[])obj;
int param1 = (int)arr(0);
string param2 = (string)arr(1);
DateTime param3 = (DateTime)arr(2);
//...
}


'VB.Net
Public Sub AsyncStart()
Dim param1 As Integer = 14
Dim param2 As String = "14"
Dim param3 As Date = Date.UtcNow

Dim thread As New System.Threading.Thread(AddressOf Me.Start)
thread.IsBackground = True
thread.Start(New Object() {param1, param2, param3})
End Sub

Private Sub Start(ByVal obj As Object)
Dim arr() As Object = DirectCast(obj, Object())
Dim param1 As Integer = DirectCast(arr(0), Integer)
Dim param2 As String = DirectCast(arr(1), String)
Dim param3 As Date = DirectCast(arr(2), Date)
'...
End Sub


روش دوم:


//C#.Net
private struct ParamList
{
public int param1;
public string param2;
public DateTime param3;
}

public void AsyncStart()
{
ParamList param = new ParamList();
param.param1 = 14;
param.param2 = "14";
param.param3 = DateTime.UtcNow;

System.Threading.Thread thread = new System.Threading.Thread(this.Start);
thread.IsBackground = true;
thread.Start(param);
}

private void Start(object obj)
{
//...
ParamList param = (ParamList)obj;
}


'VB.Net
Private Structure ParamList
Public param1 As Integer
Public param2 As String
Public param3 As Date
End Structure

Public Sub AsyncStart()
Dim param As New ParamList
param.param1 = 14
param.param2 = "14"
param.param3 = Date.UtcNow

Dim thread As New System.Threading.Thread(AddressOf Me.Start)
thread.IsBackground = True
thread.Start(param)
End Sub

Private Sub Start(ByVal obj As Object)
Dim param As ParamList = DirectCast(obj, ParamList)
'...
End Sub


روش سوم:


//C#.Net
private sealed class WapperClass
{
public int param1;
public string param2;
public System.DateTime param3;

public void AsyncStart()
{
System.Threading.Thread thread = new System.Threading.Thread(this.Start);
thread.IsBackground = true;
thread.Start(param);
}

private void Start()
{
//...
}

}

'VB.Net
Private NotInheritable Class WapperClass
Public param1 As Integer
Public param2 As String
Public param3 As Date

Public Sub AsyncStart()
Dim thread As New System.Threading.Thread(AddressOf Me.Start)
thread.IsBackground = True
thread.Start(param)
End Sub

Private Sub Start()
'...
End Sub

End Class



یه تابع هست که مثلا 2 مقدار میگیره و اجرا میشه و n دفعه خودش رو با 2 مقدار جدید راه اندازی میکنه
فرمایشاتی میفرمایید برادر، اینهاکه دیگر مسئله ندارد
با همان روش اول هم که به نظر شما بدترین روش است به همین سادگی قابل حل است!!!


//C#.Net
private void Start(object obj)
{
object[] arr = (object[])obj;
int param1 = (int)arr(0);
string param2 = (string)arr(1);
DateTime param3 = (DateTime)arr(2);

this.Start(param1, param2, param3);
}

private void Start(int param1, string param2, DateTime param3)
{
//...
if (...) this.Start(param1+1, param2+"1", param3.AddSeconds(1.0d));
//...
if (...) this.Start(param1+2, param2+"2", param3.AddSeconds(2.0d));
//...
}

'VB.Net
Private Sub Start(ByVal obj As Object)
Dim arr() As Object = DirectCast(obj, Object())
Dim param1 As Integer = DirectCast(arr(0), Integer)
Dim param2 As String = DirectCast(arr(1), String)
Dim param3 As Date = DirectCast(arr(2), Date)
Me.Start(param1, param2, param3)
End Sub

Private Sub Start(ByVal param1 As Integer, ByVal param2 As String, ByVal param3 As Date)
'...
If (...) Then Me.Start(param1+1, param2+"1", param3.AddSeconds(1.0#))
'...
If (...) Then Me.Start(param1+2, param2+"2", param3.AddSeconds(2.0#))
'...
End Sub


باز هم میبخشید که نتوانستم زودتر جواب دهم.
موفق باشید.

Alirezanet
یک شنبه 16 اسفند 1388, 00:17 صبح
توضیحاتتون خیلی مفید بود و از اینکه وقت گذاشتین خیلی ممنون ...
من یه مدت پیش از روش شما استفاده کرده بودم ولی به یه ارور بر میخوردم که الان که توضیحاتتون رو مطالعه کردم فکر میکنم مشکل جای دیگه بوده احتمالا ولی در کل خیلی کمک کرد ... :بوس:
من تا چند روز آینده این قضیه رو پیگیری میکنم و اگه مشکلی بود توی کد ها با شما در میون میذارم ...
فقط یه سوال کوچیک دیگه ...
درون روال DoWork میشه دوباره DoWork رو اجرا کرد !؟ منظور اینه توی روال از runworkerasync استفاده کرد ! (قضیه همون تو در تو بودن هستش )

gwbasic
یک شنبه 16 اسفند 1388, 07:35 صبح
اگر منظور شما را درست فهمیده باشم شما می خواهید یک متد بازگشتی را استفاده کنید
اگه یه جستجو در مورد Backgroundworker تو MSDN بزنی یک مثالی وجود داره که دنباله فیبوناچی رو محاسبه می کنه ، فکر کنم مشکلت رو حل کنه و نیازی به فراخوانی Dowork نیست بلکه اون متد هستش که خودش رو صدا می زنه و اولین بار هم توسط Dowork صدا زده می شه

موفق باشی

__H2__
یک شنبه 16 اسفند 1388, 21:55 عصر
سلام
برای فراخوانی تو در تو شما به راحتی میتوانید خود متد DoWorK (همان Start من!) را فراخوانی کنید و ایرادی ندارد آن هم یک متد است، یعنی خودتان دستی با نام متد ان را صدا بزنید (...)Me.Backgroundworker_DoWork

ولی همانطور که دوستمان gwbasic گفتند و من هم قبلاً در اخر پست 11 نوشتم شما به راحتی میتوانید یک متد دیگر با پارامترهای ورودی دلخواه (مثل دومین Start در کد آخری) داشته باشید که DoWork یا Start اصلی خودش این متد را صدا بزند و این متد پایه و اصل باشد که ورودی ها پارامتری مناسب هم داشته باشد و به هر تعداد خودش را فراخوانی کند.
(به آخرین کد پست قبلی توجه کنید.)

موفق باشید.

Alirezanet
جمعه 21 اسفند 1388, 21:10 عصر
من به backgroundworker مشکل زیر را دارم:

توی رویداد BackgroundWorker1.DoWork به یک combobox دسترسی پیدا می کنم که خطای زیر را می ده:

Cross-thread operation not valid: Control 'vilageComboBox' accessed from a thread other than the thread it was created on

چه کنم؟


کد زیر را تو رویداد لود فرم اصلیت یا توی constructor فرم اصلیت بعد از initializeComponent() بذار





Control.CheckForIllegalCrossThreadCalls = false;


موفق باشید
مهدی کیانی


خوب میشه یکی در مورد این مشکل و جوابش یه توضیح بده ... از نظر کارایی نمیگم درست کار میکنه ولی دقیقا این کد چیکار میکنه ؟!!



Control.CheckForIllegalCrossThreadCalls = false;

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

یکی از بچه ها هم یه سوال کرد که نتونستم جوابشو بدم گفتم شما شاید بتونین ! :

اولا

چرا کدی که بدون استفاده از BackGroundWorker مثلا طی 10 ثانیه کارش تموم میشه با استفاده از این کنترل در حدود 1 دقیقه طول میکشه !؟ (منظور که خیلی بیشتر طول میکشه ؟! )
چیکار میشه کرد سرعت کار هم بالا بره ؟! مثل کارایی ؟! امکانش هست ! ؟

من که نتونستم جواب بدم شما کمک کنین!

__H2__
یک شنبه 23 اسفند 1388, 19:12 عصر
سلام

از نظر کارایی نمیگم[،] درست کار میکنهCOLOR="Olive"][،][/COLOR]
نمیدانم منظورتان آن بود که درست کار میکند یا نه؟! بستگی به ویرگولی دارد که نگذاشتید !
ولی بدانید که همیشه درست کار نمیکند! و این راهش نیست.

دات نت به صورت داخلی ریسمانی را که فرامین کنترلرها را اجرا میکند چک میکند تا مطمئن شود همان ریسمان اصلی است (ریسمانی که صف پیام های ویندوز را در دست دارد) و گرنه خطا میدهد.

خصیصه CheckForIllegalCrossThreadCalls این بررسی و تست توسط دات نت را فعال و غیر فعال میکند.
(که پیشنهاد میکنم دستش نزنید و بگذارید فعال باشد.)

را حل اصلی و صحیح کامل استفاده از خصیصه InvokeRequired به همراه متد Invoke یا BeginInvoke است.
بدیهی است که اگر همین سایت برنامه نویس را با این کلمات جستجو کنید مطالب خوبی خواهید یافت.

من قبلاً در تاپیک سایت دیگری این موارد را تشریح کردم...
این کد صحیح نمادین:


private delegate void TextReportDelegate(string value);
//__________________________________________________ ______________________

public void TextReport(string text)
{
if (this.InvokeRequired)
{
//[run in new thread]
this.BeginInvoke(new TextReportDelegate(this.TextReport), text); //switch and pass to main thread.
return;
}
//---
//[run in main thread]
//...
this.TextBox1.Text = text;
//...
}
//__________________________________________________ ______________________



//Start ... [run in main thread]
private void btnStart_Click(object sender, EventArgs e)
{
if (this.backgroundWorker1.IsBusy) return;
//-----
this.btnStart.Enabled = false;
this.TextReport("Start ...");
object arg;
//...
//...arg = ...
//...
//-----
this.backgroundWorker1.RunWorkerAsync(arg); //start new thread.
}
//__________________________________________________ ______________________

//Work ... [run in new thread]
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
object arg = e.Argument;
object result;
//-----
//...
//...while(...)
//...
//...Function1(...)
//...
this.TextReport("Progress ...");
//...
//...Function2(...)
//...
//...result = ...
//...
//-----
e.Result = result;
}
//__________________________________________________ ______________________

//End. [run in main thread]
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
object result = e.Result;
//-----
//...
this.TextReport("Completed.");
//...
//...MsgBox ...
//...
//-----
this.btnStart.Enabled = true;
}
//__________________________________________________ ______________________

این هم توضیحاتش:
http://forum.p30world.com/showthread.php?p=4690830#post4690830


من که نتونستم جواب بدم شما کمک کنین!
در شرایط عادی و بدون تغییر تنظیم ریسمان سرعت اجرا نباشد فرقی کند.
گمانم کد این دوست شما مشکل دارد.
کسی در تالار دیگری کندی سرعت شکایت داشت، کدش را دیدم رفتم تو هنگ!!!
حالا شما میفرمائید فقط در ریسمان جدید مشکل دارد.
اگر تفاوت کم باشد که هیچ وگرنه باید کد باشد تا بتوان مشکل را تشخیص داد.

موفق باشید.