نمایش نتایج 1 تا 15 از 15

نام تاپیک: نحوه استفاده از BackgroundWorker برای همزمان سازی

  1. #1
    کاربر دائمی آواتار Saeed_m_Farid
    تاریخ عضویت
    تیر 1386
    محل زندگی
    فضای تهی میان دیوارها
    سن
    44
    پست
    1,046

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

    سلام
    دوستان عزیز سی شارپ کار گل، خسته نباشید.
    راستش من زیاد تو پروژه های Win32 Form C#‎‎‎‎‎‎‎.Net کار نکردم، اکثراً اگه با دات نت هم کار داشتم با وب سرویس ها کار داشتم تا UI و ...
    بگذریم، می خواستم ببینم چطوری میشه برای Synchronize استفاده کردن (یا بقول دات نت ها Thread-safe کردن) عناصر روی فرم از BackgroundWorker استفاده کرد؟ تو اینجا یه توضیحاتی در این زمینه داده ولی زیاد با کار من همخوانی نداره یا من درست متوجه نمیشم؛ دو تا راه حل اونجا پیشنهاد شده که یکیش توی خود Thread فرعی داره یه تابع Callback استفاده میکنه، که من اینکار رو نمیخوام بکنم و اون یکی هم از BackgroundWorker استفاده کرده و این بنظرم خیلی بهتر اومد ولی نتونستم implement اش بکنم؛ برای اینکه بهتر منظورم رو بگیرید (با اینکه ممکنه تکراری باشه ولی من پاسخ مناسب پیدا نکردم) : باید بگم من برای گرفتن محتویات چندین جدول و نوشتن همزمان log مراحل دچار مشکل شدم! یعنی کاری که خیلی راحت همیشه تو دلفی (بخاطر عادت به سینتکس اش) انجام میدم رو اینجا نمی تونم انجام بدم، کد مورد نظر (نمونه هست نه اصلی) می تونه به شکل زیر باشه که من از اساتید محترم میخوام قسمت کامنت شده رو دقت کنند، اون خط قرمز جایی هست که به مشکل برخوردم و نتونستم ادامه بدم :

            // lstboxLogs = Is a ListBox to log events.
    private void addLog(object log)
    {
    string msg = string.Format("{0:F} > {1}", DateTime.Now, log);
    lstboxLogs.Items.Add(msg);
    }

    // cbTablesName = A ComboBox contain Table(s) name
    // GetHotBillTableContents = A WebMethod return Dataset by TableName
    // dataGV = A DataGridView for show Dataset contains.
    private void update_sql_tables()
    {
    for (int idx = 0; idx < cbTablesName.Items.Count - 1; idx++)
    {
    addLog("Fetch Table <" + cbTablesName.Items[idx].ToString() + "> Contents ...");
    DataSet setting_ds = hotbill.GetHotBillTableContents(cbTablesName.Items[idx].ToString());
    addLog(string.Format("Table <{0}> have [{1}] records.",
    cbTablesName.Items[idx].ToString(),
    setting_ds.Tables[0].Rows.Count));
    if (setting_ds.Tables.Count > 0)
    {
    dataGV.DataSource = setting_ds.Tables[0];
    dataGV.AutoResizeColumns();
    Refresh();
    Thread.Sleep(1000); // replace with a retardation procedur ...
    }
    }
    }

    private void btnUpdateSettings_Click(object sender, EventArgs e)
    {
    if (MessageBox.Show("Are you sure to update all tables?", "Warning",
    MessageBoxButtons.YesNo,
    MessageBoxIcon.Question,
    MessageBoxDefaultButton.Button1) == DialogResult.Yes)
    {
    btnGetTables_Click(sender, e);

    addLog(string.Format("{0} <{1}> {2}", "Start update", cbTablesName.Items.Count, "Tables"));
    /*
    Thread th = new Thread(new ThreadStart(update_sql_tables));
    th.IsBackground = true;
    th.Start();
    */
    update_sql_tables(); // I want do this function in thread, and also log steps ...
    }
    }

    فکر کنم تا جایی که میشد توضیحات درون کد هست، ولی بازم اگه نامفهوم بود بفرمایید تا بیشتر توضیح بدم ...

    ممنون.

  2. #2
    کاربر دائمی آواتار Saeed_m_Farid
    تاریخ عضویت
    تیر 1386
    محل زندگی
    فضای تهی میان دیوارها
    سن
    44
    پست
    1,046

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    متاسفانه تو بلاک [SOURCE] تگ [COLOR] درست عمل نمی کنه و بالطبع خط قرمزی هم تو کد بالا موجود نبود! (قابل توجه vBulletin® Version 3.8.0 )
    خلاصه اش اینکه من هرجا از عناصر روی فرم تو تابع update_sql_tables استفاده کردم، مشکل مزبور [1] هست و مثلاً lstboxLogs یاdataGV رو صدا کردم به مشکل برخوردم و معلوم بود که به مشکل برمیخورم، چون از Thread ای دارم اونها رو فراخوانی می کنم که مالکِشون نیست؛ ولی راه پیاده سازی برای فراخوانی Thread-safe عناصر روی فرم پیدا نکردم!
    ممنون میشم اگه با توضیحات راهنمایی کنید ...

    [1] مشکل مزیور =
    System.InvalidOperationException was unhandled
    Message="Cross-thread operation not valid: Control 'lstboxLogs' accessed from a thread other than the thread it was created on."
    Source="System.Windows.Forms"
    StackTrace:
    at System.Windows.Forms.Control.get_Handle()
    at System.Windows.Forms.Control.SendMessage(Int32 msg, Int32 wparam, String lparam)
    at System.Windows.Forms.ListBox.NativeAdd(Object item)
    at System.Windows.Forms.ListBox.ObjectCollection.AddI nternal(Object item)
    at System.Windows.Forms.ListBox.ObjectCollection.Add( Object item)
    at TestHotBilling.frmHotBilling.addLog(Object log) in ..\..\..\..\frmTesterMain.cs:line 152
    at TestHotBilling.frmHotBilling.update_sql_tables() in ..\..\..\..\frmTesterMain.cs:line 162
    at System.Threading.ThreadHelper.ThreadStart_Context( Object state)
    at System.Threading.ExecutionContext.Run(ExecutionCon text executionContext, ContextCallback callback, Object state)
    at System.Threading.ThreadHelper.ThreadStart()
    InnerException:

  3. #3
    کاربر دائمی آواتار Saeed_m_Farid
    تاریخ عضویت
    تیر 1386
    محل زندگی
    فضای تهی میان دیوارها
    سن
    44
    پست
    1,046

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

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

    تو کد زیر از روش delegate و Callback استفاده کردم و با اینکه هیچ سوادی تو #C ندارم تونستم اینطوری (با استفاده از msdn و بر پایه سواد دلفی!) جواب بگیرم. دوستان اگه مشکلی تو کد من می بینن، خیلی خوشحال میشم که رفع اشکال کنند تا دوستان دیگه هم بعداً (با دیدن این کد) به اشتباه نیفتن ...



    // This delegate enables asynchronous calls for adding
    // the text property into a ListBox control.
    delegate void AddTextCallback(string text);

    // This method is passed in to the AddTextCallBack delegate
    // to add the Text property of lstboxLogs.
    private void AddText(string text)
    {
    this.lstboxLogs.Items.Add(text);
    }

    // lstboxLogs = Is a ListBox to log events.
    private void addLog(object log)
    {
    string msg = string.Format("{0:F} > {1}", DateTime.Now, log);

    // Check if this method is running on a different thread
    // than the thread that created the control.
    if (this.lstboxLogs.InvokeRequired)
    {
    // It's on a different thread, so use Invoke.
    AddTextCallback d = new AddTextCallback(AddText);
    this.Invoke
    (d, new object[] { msg + " (From Thread)" });
    }
    else
    {
    // It's on the same thread, no need for Invoke
    AddText(msg);
    }
    }

    // This delegate enables asynchronous calls for setting
    // the Dataset property to a DataGridView control.
    delegate void Update_dataGVCallback(DataTable table);

    // This method is passed in to the Update_dataGVCallback delegate
    // to set the DataTable property to dataGV.
    private void Update_dataGV(DataTable table)
    {
    if (this.dataGV.InvokeRequired)
    {
    Update_dataGVCallback d = new Update_dataGVCallback(Update_dataGV);
    this.Invoke
    (d, new object[] {table});
    }
    else
    {
    this.dataGV.DataSource = table;
    this.dataGV.AutoResizeColumns();
    this.Refresh();
    }
    }

    // cbTablesName = A ComboBox contain Table(s) name
    // GetHotBillTableContents = A WebMethod return Dataset by TableName
    // dataGV = A DataGridView for show Dataset contains.
    private void update_sql_tables()
    {
    for (int idx = 0; idx < cbTablesName.Items.Count - 1; idx++)
    {
    addLog("Fetch Table <" + cbTablesName.Items[idx].ToString() + "> Contents ...");
    DataSet setting_ds = hotbill.GetHotBillTableContents(cbTablesName.Items[idx].ToString());
    addLog(string.Format("Table <{0}> have [{1}] records.",
    cbTablesName.Items[idx].ToString(),
    setting_ds.Tables[0].Rows.Count));
    if (setting_ds.Tables.Count > 0)
    {
    Update_dataGV(setting_ds.Tables[0]);
    Thread.Sleep(1000); // replace with a retardation procedur ...
    }
    }
    }

    private void btnUpdateSettings_Click(object sender, EventArgs e)
    {
    if (MessageBox.Show("Are you sure to update all tables?", "Warning",
    MessageBoxButtons.YesNo,
    MessageBoxIcon.Question,
    MessageBoxDefaultButton.Button1) == DialogResult.Yes)
    {
    btnGetTables_Click(sender, e);

    addLog(string.Format("{0} <{1}> {2}", "Start update", cbTablesName.Items.Count, "Tables"));
    Thread th = new Thread(new ThreadStart(update_sql_tables));
    th.IsBackground = true;
    th.Start();
    //update_sql_tables(); // I want do this function in thread, and also log steps ...
    }
    }


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

  4. #4

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    استفاده از Control.Invoke تقریبا مشابه استفاده از TThread.Queue در دلفی هست. یک مدخل جدید در صف Thread مالک کنترل ایجاد میکنه، و به همراه آن یک method pointer هم ارسال میکنه تا اون Thread بدونه چه متدی رو باید اجرا کنه. البته TThread.Queue فقط با Thread اصلی برنامه کار میکنه، چون در VCL فقط Thread اصلی مالک اشیاء ویژوال هست، ولی در دات نت Control.Invoke دنبال Thread مالک کنترل میگرده، و بعد از پیدا کردن آن، پیام را بهش ارسال میکنه.

    استفاده از BackgroundWorker از نظر Performance نباید تفاوت خاصی با Control.Invoke داشته باشه، غیر از اینکه در Control.Invoke یک مرحله جستجوی Thread هم وجود داره. البته من عملا تست نکردم که تفاوت Performanceشان با هم چقدر هست.
    در BackgroundWorker تعامل شما با Thread اصلی هست، و فقط از طریق دو رویداد RunWorkerCompleted و ProgressChanged انجام میشه، پس کدهای شما مثل Add_log یا Update_dataGV باید در یکی از این دو رویداد فراخوانی بشند، البته در این صورت دیگه نیازی به بررسی IsInvokeRequired نیست.
    در دلفی بطور استاندارد معادلی برای BackgroundWorker وجود نداره، ولی میشه مشابه آن را نوشت، یا از کتابخانه های رایگان که قابلیت مشابهی ارائه می کنند، استفاده کرد، مثل OmniThread.


    وَ سَيَعْلَمُ الَّذِينَ ظَلَمُوا [آل محمد حقهم] أَيَّ مُنْقَلَبٍ يَنْقَلِبُونَ - الشعراء (227)
    و ظالمین [حق آل محمد (ص) ] به زودی خواهند دانست که به کدام بازگشتگاه بازخواهند گشت.

  5. #5
    کاربر دائمی آواتار Saeed_m_Farid
    تاریخ عضویت
    تیر 1386
    محل زندگی
    فضای تهی میان دیوارها
    سن
    44
    پست
    1,046

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    نقل قول نوشته شده توسط علی کشاورز مشاهده تاپیک
    ...
    استفاده از BackgroundWorker از نظر Performance نباید تفاوت خاصی با Control.Invoke داشته باشه، غیر از اینکه در Control.Invoke یک مرحله جستجوی Thread هم وجود داره. البته من عملا تست نکردم که تفاوت Performanceشان با هم چقدر هست.
    ...
    در BackgroundWorker تعامل شما با Thread اصلی هست، و فقط از طریق دو رویداد RunWorkerCompleted و ProgressChanged انجام میشه، پس کدهای شما مثل Add_log یا Update_dataGV باید در یکی از این دو رویداد فراخوانی بشند، البته در این صورت دیگه نیازی به بررسی IsInvokeRequired نیست.
    مرسی، بازم شما علی آقا ...
    (اینهمه تغییرات دادین تو سایت بازم خودتون زبل خان هستید که! )

    گذشته از شوخی؛ پس بنظر شما کد بالا عملاً مشکلی نداره؟ حالا Performance اش بماند، این کد Thread-safeهست دیگه ان شا... ؟
    راستش یکمی ناجور بنظر میرسه که داخل خود تابعی که قرار هست Asynchron فراخوانی بشه، یه CallBack تنظیم (Set) کنیم! اونهم با این سینتکس عجیب که new object رو Invoke میکنه و ...

    بازم ممنون.

  6. #6

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    گذشته از شوخی؛ پس بنظر شما کد بالا عملاً مشکلی نداره؟ حالا Performance اش بماند، این کد Thread-safeهست دیگه ان شا... ؟
    من از جزئیاتش اطلاعی ندارم، Visual Studio هم الان ندارم که بخوام تست کنم، ولی منطق کار درست هست، و کدهای مربوط به تغییر UI از سایر کدها جدا شدند، و توسط Threadهای مالک اون اشیاء ویژوال تغییر می کنند.

    راستش یکمی ناجور بنظر میرسه که داخل خود تابعی که قرار هست Asynchron فراخوانی بشه، یه CallBack تنظیم (Set) کنیم! اونهم با این سینتکس عجیب که new object رو Invoke میکنه و ...
    خب دیگه، هر زبانی شکل و شمایل خودش رو داره.


    وَ سَيَعْلَمُ الَّذِينَ ظَلَمُوا [آل محمد حقهم] أَيَّ مُنْقَلَبٍ يَنْقَلِبُونَ - الشعراء (227)
    و ظالمین [حق آل محمد (ص) ] به زودی خواهند دانست که به کدام بازگشتگاه بازخواهند گشت.

  7. #7

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    سلام
    يا BackgroundWorker كار مي كردم كه در هنگام اجرا متوجه شدم كه ThreadSafe نيست. دست به دامان MSDN شدم كه راه حل خوبي براش ارائه كرده:


    عنوان مطلب :

    How to: Make Thread-Safe Calls to Windows Forms Controls


    لينك آموزش داخل msdn2005 :

    ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_fxmclictl/html/138f38b6-1099-4fd5-910c-390b41cbad35.htm



    اين هم سورس كد:

    Imports System
    Imports System.ComponentModel
    Imports System.Threading
    Imports System.Windows.Forms

    Public Class form3
    Inherits Form

    ' This delegate enables asynchronous calls for setting
    ' the text property on a TextBox control.
    Delegate Sub SetTextCallback(ByVal [text] As String)

    ' This thread is used to demonstrate both thread-safe and
    ' unsafe ways to call a Windows Forms control.
    Private demoThread As Thread = Nothing

    ' This BackgroundWorker is used to demonstrate the
    ' preferred way of performing asynchronous operations.
    Private WithEvents backgroundWorker1 As BackgroundWorker

    Private textBox1 As TextBox
    Private WithEvents setTextUnsafeBtn As Button
    Private WithEvents setTextSafeBtn As Button
    Private WithEvents setTextBackgroundWorkerBtn As Button

    ' Private components As System.ComponentModel.IContainer = Nothing


    Public Sub New()
    InitializeComponent()
    End Sub


    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing AndAlso Not (components Is Nothing) Then
    components.Dispose()
    End If
    MyBase.Dispose(disposing)
    End Sub


    ' This event handler creates a thread that calls a
    ' Windows Forms control in an unsafe way.
    Private Sub setTextUnsafeBtn_Click( _
    ByVal sender As Object, _
    ByVal e As EventArgs) Handles setTextUnsafeBtn.Click

    Me.demoThread = New Thread( _
    New ThreadStart(AddressOf Me.ThreadProcUnsafe))

    Me.demoThread.Start()
    End Sub


    ' This method is executed on the worker thread and makes
    ' an unsafe call on the TextBox control.
    Private Sub ThreadProcUnsafe()
    Me.textBox1.Text = "This text was set unsafely."
    End Sub

    ' This event handler creates a thread that calls a
    ' Windows Forms control in a thread-safe way.
    Private Sub setTextSafeBtn_Click( _
    ByVal sender As Object, _
    ByVal e As EventArgs) Handles setTextSafeBtn.Click

    Me.demoThread = New Thread( _
    New ThreadStart(AddressOf Me.ThreadProcSafe))

    Me.demoThread.Start()
    End Sub


    ' This method is executed on the worker thread and makes
    ' a thread-safe call on the TextBox control.
    Private Sub ThreadProcSafe()
    Me.SetText("This text was set safely.")
    End Sub

    ' This method demonstrates a pattern for making thread-safe
    ' calls on a Windows Forms control.
    '
    ' If the calling thread is different from the thread that
    ' created the TextBox control, this method creates a
    ' SetTextCallback and calls itself asynchronously using the
    ' Invoke method.
    '
    ' If the calling thread is the same as the thread that created
    ' the TextBox control, the Text property is set directly.

    Private Sub SetText(ByVal [text] As String)

    ' InvokeRequired required compares the thread ID of the
    ' calling thread to the thread ID of the creating thread.
    ' If these threads are different, it returns true.
    If Me.textBox1.InvokeRequired Then
    Dim d As New SetTextCallback(AddressOf SetText)
    Me.Invoke(d, New Object() {[text]})
    Else
    Me.textBox1.Text = [text]
    End If
    End Sub

    ' This event handler starts the form's
    ' BackgroundWorker by calling RunWorkerAsync.
    '
    ' The Text property of the TextBox control is set
    ' when the BackgroundWorker raises the RunWorkerCompleted
    ' event.
    Private Sub setTextBackgroundWorkerBtn_Click( _
    ByVal sender As Object, _
    ByVal e As EventArgs) Handles setTextBackgroundWorkerBtn.Click
    Me.backgroundWorker1.RunWorkerAsync()
    End Sub


    ' This event handler sets the Text property of the TextBox
    ' control. It is called on the thread that created the
    ' TextBox control, so the call is thread-safe.
    '
    ' BackgroundWorker is the preferred way to perform asynchronous
    ' operations.
    Private Sub backgroundWorker1_RunWorkerCompleted( _
    ByVal sender As Object, _
    ByVal e As RunWorkerCompletedEventArgs) _
    Handles backgroundWorker1.RunWorkerCompleted
    Me.textBox1.Text = _
    "This text was set safely by BackgroundWorker."
    End Sub

    #Region "Windows Form Designer generated code"


    Private Sub InitializeComponent()
    Me.textBox1 = New System.Windows.Forms.TextBox()
    Me.setTextUnsafeBtn = New System.Windows.Forms.Button()
    Me.setTextSafeBtn = New System.Windows.Forms.Button()
    Me.setTextBackgroundWorkerBtn = New System.Windows.Forms.Button()
    Me.backgroundWorker1 = New System.ComponentModel.BackgroundWorker()
    Me.SuspendLayout()
    '
    ' textBox1
    '
    Me.textBox1.Location = New System.Drawing.Point(12, 12)
    Me.textBox1.Name = "textBox1"
    Me.textBox1.Size = New System.Drawing.Size(240, 20)
    Me.textBox1.TabIndex = 0
    '
    ' setTextUnsafeBtn
    '
    Me.setTextUnsafeBtn.Location = New System.Drawing.Point(15, 55)
    Me.setTextUnsafeBtn.Name = "setTextUnsafeBtn"
    Me.setTextUnsafeBtn.TabIndex = 1
    Me.setTextUnsafeBtn.Text = "Unsafe Call"
    '
    ' setTextSafeBtn
    '
    Me.setTextSafeBtn.Location = New System.Drawing.Point(96, 55)
    Me.setTextSafeBtn.Name = "setTextSafeBtn"
    Me.setTextSafeBtn.TabIndex = 2
    Me.setTextSafeBtn.Text = "Safe Call"
    '
    ' setTextBackgroundWorkerBtn
    '
    Me.setTextBackgroundWorkerBtn.Location = New System.Drawing.Point(177, 55)
    Me.setTextBackgroundWorkerBtn.Name = "setTextBackgroundWorkerBtn"
    Me.setTextBackgroundWorkerBtn.TabIndex = 3
    Me.setTextBackgroundWorkerBtn.Text = "Safe BW Call"
    '
    ' backgroundWorker1
    '
    '
    ' form3
    '
    Me.ClientSize = New System.Drawing.Size(268, 96)
    Me.Controls.Add(setTextBackgroundWorkerBtn)
    Me.Controls.Add(setTextSafeBtn)
    Me.Controls.Add(setTextUnsafeBtn)
    Me.Controls.Add(textBox1)
    Me.Name = "form3"
    Me.Text = "form3"
    Me.ResumeLayout(False)
    Me.PerformLayout()
    End Sub 'InitializeComponent

    #End Region

    <STAThread()> _
    Shared Sub Main()
    Application.EnableVisualStyles()
    Application.Run(New form3())
    End Sub
    End Class



  8. #8
    کاربر دائمی آواتار Saeed_m_Farid
    تاریخ عضویت
    تیر 1386
    محل زندگی
    فضای تهی میان دیوارها
    سن
    44
    پست
    1,046

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    نقل قول نوشته شده توسط bashiry مشاهده تاپیک
    سلام
    يا BackgroundWorker كار مي كردم كه در هنگام اجرا متوجه شدم كه ThreadSafe نيست. دست به دامان MSDN شدم كه راه حل خوبي براش ارائه كرده ...
    سلام
    دست شما درد نکنه ولی این که همون لینکی هست که من تو پست اول گذاشتم! شما فقط کد VB اش رو کپی کردید که متاسفانه به درد من نمیخوره ...
    نقل قول نوشته شده توسط Saeed_m_Farid مشاهده تاپیک
    ... تو اینجا یه توضیحاتی در این زمینه داده ولی زیاد با کار من همخوانی نداره ...
    مشکل من از طریق Invoke و Callback حل شد (تو پست سوم همین تاپیک) ولی مشتاقم تا دوستانی که راه حل عملی برای پیاده سازی این کد با BackgroundWorker دارند، ارائه کنند تا نحوه کاربرد اون رو هم یاد بگیریم؛ یعنی من درون تابعی که به Thread معرفی می کنم، بتونم با BackgroundWorker مثلاً دیتاگرید رو Asynchron پر کنم یا addlog رو فراخوانی کنم و ...

    یه چیزی شبیه این، ولی برای کد ذکر شده :

    // This method starts BackgroundWorker by calling
    // RunWorkerAsync. The Text property of the TextBox control
    // is set by a method running in the main thread
    // when BackgroundWorker raises the RunWorkerCompleted event.
    private void setTextBackgroundWorkerBtn_Click(
    object sender,
    EventArgs e)
    {
    this.backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
    this.backgroundWorker1.RunWorkerCompleted +=
    new System.ComponentModel.RunWorkerCompletedEventHandl er(this.backgroundWorker1_RunWorkerCompleted);
    this.backgroundWorker1.RunWorkerAsync();

    // Continue in the main thread.
    textBox1.Text = "Written by the main thread.";
    }

    // This method does the work you want done in the background.
    void backgroundWorker1_DoWork (object sender, DoWorkEventArgs e)
    {
    // Wait two seconds to simulate some background work
    // being done.
    Thread.Sleep(2000);

    // You could use the same technique as in the
    // ThreadProcSafe method to set textBox1.Text here, but
    // the preferred method is to do it from the Completed
    // event handler which runs in the same thread as the one
    // that created the control.
    }

    // This method is called by BackgroundWorker's
    // RunWorkerCompleted event. Because it runs in the
    // main thread, it can safely set textBox1.Text.
    private void backgroundWorker1_RunWorkerCompleted(
    object sender,
    RunWorkerCompletedEventArgs e)
    {
    this.textBox1.Text =
    "Written by the main thread after the background thread completed.";
    }


    بازم ممنون.
    آخرین ویرایش به وسیله Saeed_m_Farid : شنبه 12 دی 1388 در 15:16 عصر دلیل: اضافه کردن نقل قول

  9. #9

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    می خواستم ببینم چطوری میشه برای Synchronize استفاده کردن (یا بقول دات نت ها Thread-safe کردن)
    سلام.
    واژه Thread-Safe ربطی به .NET Framework نداره و قبل از اونهم توسط برنامه نویسان C/C++‎ استفاده میشده (اگر چه اونها Synchronization رو بیشتر استفاده میکنن)، بنابراین این بخش از گفته شما که "بقول دات نت کارها..." چندان صحیح نیست.

    اما در مورد BackgroundWorker... ببینید. فرض کنیم شما میخواهید کاری رو که مدت زمان زیادی بطول می انجامه رو در یک Worker Thread انجام بدید. برای اینکار، دستورالعملهای مزبور رو در Thread دیگه ای انجام میدید و Notification های لازم (در صورت نیاز) رو به UI Thread (یا همون Main Thread) ارسال میکنید. BackgroundWorker اینکارو خیلی ساده کرده. شما میتونید توی DoWork کار زمانبر خودتون رو انجام بدید... و هر از گاهی (بسته به نیاز) Main-Thread رو از روند کار Worker Thread مطلع کنید. مثلا:


    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
    //Our lengthy operation
    for (int i = 0; i < 100; i++)
    {
    backgroundWorker1.ReportProgress(i + 1, "whatever state");
    }
    }


    بعنوان نمونه من توی لوپ فوق دارم یک کار زمانبر رو انجام میدم. و در مراحلی (اینجا بازای هر بار تغییر i) دارم روند اجرای Worker Thread رو به UI Thread اطلاع میدم. اما حواستون باشه که برای اجرای کد فوق، حتما باید دستور زیر قبلش از راه اندازی Thread اجرا بشه:

    backgroundWorker1.WorkerReportsProgress = true;


    حالا، هنگامیکه توی UI Thread خودم، از پیشرفت کار Worker Thread مطلع شدم، میتونم کارم با UI رو انجام بدم:


    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
    string userState = e.UserState as string;
    Debug.Assert(userState == "whatever state");
    }


    اینجا، میتونم براحتی برم و تغییرات لازم رو روی UI اعمال کنم. ضمن اینکه، درصد پیشرفت کار و UserState دلخواهم هم از Worker Thread بدست UI-Thread رسیده که در مثال بالا، string ای بود که ...

    برای Cancel کردن Worker Thread هم میتونید از CancelAsync استفاده کنید. فقط حواستون باشه که خودتون باید توی Interval های دلخواهتون CancellationPending رو چک کنید تا اگر true بود، کار Worker Thread رو خاتمه داده و از تابع DoWork خارج بشید. (این کار مایکروسافت واقعا احمقانه بوده، جای اینکه Event رو بشه Signal کرد و ... اومده از یک متغیر boolean برای cancel کردن کار استفاده میکنه. که خوب، اگر برنامه نویس حواسش نباشه، کد نهایی cpu-usage رو میتونه بالا ببره).

    موفق باشید.

  10. #10
    کاربر دائمی آواتار Saeed_m_Farid
    تاریخ عضویت
    تیر 1386
    محل زندگی
    فضای تهی میان دیوارها
    سن
    44
    پست
    1,046

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    نقل قول نوشته شده توسط mehdi.mousavi مشاهده تاپیک
    سلام.
    واژه Thread-Safe ربطي به .NET Framework نداره و قبل از اونهم توسط برنامه نويسان C/C++‎‎‎‎‎‎‎‎ استفاده ميشده (اگر چه اونها Synchronization رو بيشتر استفاده ميکنن)، بنابراين اين بخش از گفته شما که "بقول دات نت کارها..." چندان صحيح نيست.
    سلام، مثل همیشه آقا مهدی خشن! حالا چندان صحیح نباشه، چی میشه مگه؟ میخواستم زود با بچه ها پسرخاله بشیم، تحویلمون بگیرن ...
    نقل قول نوشته شده توسط mehdi.mousavi مشاهده تاپیک
    برای Cancel کردن Worker Thread هم میتونید از CancelAsync استفاده کنید. فقط حواستون باشه که خودتون باید توی Interval های دلخواهتون CancellationPending رو چک کنید تا اگر true بود، کار Worker Thread رو خاتمه داده و از تابع DoWork خارج بشید. (این کار مایکروسافت واقعا احمقانه بوده، جای اینکه Event رو بشه Signal کرد و ... اومده از یک متغیر boolean برای cancel کردن کار استفاده میکنه. که خوب، اگر برنامه نویس حواسش نباشه، کد نهایی cpu-usage رو میتونه بالا ببره).
    بیخیال Cancle، آقا من تو working اش مشکل دارم!
    از راهنمایی هاتون خیلی مرسی، دو قرونی افتاد و با توضیحات شما و راهنمایی های MSDN کد من شد بصورت زیر :
    یعنی بجای CallBack از BackgroundWorker استفاده کردم.

    private void bgwTablUpdater_DoWork(object sender, DoWorkEventArgs e)
    {
    bool bAllTransfered = true;
    if ((MessageBox.Show("Are you sure to update all tables?", "Warning",
    MessageBoxButtons.YesNo,
    MessageBoxIcon.Question,
    MessageBoxDefaultButton.Button1) == DialogResult.Yes) &&
    (lstboxTables.Items.Count > 0))
    {
    int idx, iPercent = 0;
    for (idx = 0; idx < lstboxTables.Items.Count; idx++)
    {
    try
    {
    Select_TableItem(idx);
    iPercent = (idx * 100) / lstboxTables.Items.Count;
    DataSet setting_ds = hotbill.GetHotBillTableContents(lstboxTables.Items[idx].ToString());
    bgwTablUpdater.ReportProgress(iPercent, string.Format("[{0}] Table <{1}> have [{2}] records.",
    idx + 1,
    lstboxTables.Items[idx].ToString(),
    setting_ds.Tables[0].Rows.Count));
    if (setting_ds.Tables.Count > 0)
    {
    Update_dataGV(setting_ds.Tables[0]);
    int tdx = sqlTablesList.IndexOf(lstboxTables.Items[idx].ToString());
    if (!transferTable(lstboxTables.Items[idx].ToString(),
    setting_ds.Tables[0],
    (tdx >= 0)))
    break;
    }
    }
    catch (Exception ex)
    {
    bgwTablUpdater.ReportProgress(iPercent, "[ER]: "+ex.Message);
    bAllTransfered = false;
    }
    }
    if (bAllTransfered)
    bgwTablUpdater.ReportProgress(100, "Process Completed Successfull.");
    else
    bgwTablUpdater.ReportProgress(-1, "[WR] Process Not Completed.");
    }
    else
    MessageBox.Show("There is not any Update Table existed in list!"
    + "\nTry \"Get HotBill Tables\" first", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
    }

    //=================

    private void bgwTablUpdater_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
    AddText(string.Format("[{0}%] : {1}",
    (e.ProgressPercentage).ToString() +
    e.UserState as string));
    }

    //=================

    private void bgwTablUpdater_RunWorkerCompleted(object sender,
    RunWorkerCompletedEventArgs e)
    {
    AddText("Written by the main thread after the background thread completed.");
    }

    //=================

    private void btnUpdateSettings_Click(object sender, EventArgs e)
    {
    if (MessageBox.Show("Are you sure to update all tables?", "Warning",
    MessageBoxButtons.YesNo,
    MessageBoxIcon.Question,
    MessageBoxDefaultButton.Button1) == DialogResult.Yes)
    {
    btnUpdateSettings.Enabled = false;
    bgwTablUpdater.DoWork += new DoWorkEventHandler(bgwTablUpdater_DoWork);
    bgwTablUpdater.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgwTablUpdater_RunW orkerCompleted);
    bgwTablUpdater.ProgressChanged += new ProgressChangedEventHandler(bgwTablUpdater_Progres sChanged);
    bgwTablUpdater.WorkerReportsProgress = true;
    bgwTablUpdater.RunWorkerAsync();
    }
    }


    یه سوال : نام توابعی که از ترکیب پسوندها (DoWork و RunWorkerCompleted و ...) و نام تابع اصلی درست میشن و Event Handler ها رو درست می کنند، میشه عوض بشن؟ یعنی نام تابع من یه چیز دیگه باشه : مثلاً bgwTablUpdater_DoWork بشه DoWorkTablUpdater، فکر نکنم نشه! چون من دارم دستی Event Handler رو اختصاص میدم، درسته؟

    مشکل : یک استثناء یا بهتر اگر گویم : اعتراض (بیگانگان Exception گویند) خفن دریافت می کنیم، بدین سان : Exception has been thrown by the target of an invocation.
    و جزئیات اش مشتمل بر موارد ذیل می گردد:


    System.Reflection.TargetInvocationException was unhandled
    Message="Exception has been thrown by the target of an invocation."
    Source="mscorlib"
    StackTrace:
    at System.RuntimeMethodHandle._InvokeMethodFast(Objec t target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
    at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
    at System.Delegate.DynamicInvokeImpl(Object[] args)
    at System.Windows.Forms.Control.InvokeMarshaledCallba ckDo(ThreadMethodEntry tme)
    at System.Windows.Forms.Control.InvokeMarshaledCallba ckHelper(Object obj)
    at System.Threading.ExecutionContext.runTryCode(Objec t userData)
    at System.Runtime.CompilerServices.RuntimeHelpers.Exe cuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
    at System.Threading.ExecutionContext.RunInternal(Exec utionContext executionContext, ContextCallback callback, Object state)
    at System.Threading.ExecutionContext.Run(ExecutionCon text executionContext, ContextCallback callback, Object state)
    at System.Windows.Forms.Control.InvokeMarshaledCallba ck(ThreadMethodEntry tme)
    at System.Windows.Forms.Control.InvokeMarshaledCallba cks()
    at System.Windows.Forms.Control.WndProc(Message& m)
    at System.Windows.Forms.Control.ControlNativeWindow.O nMessage(Message& m)
    at System.Windows.Forms.Control.ControlNativeWindow.W ndProc(Message& m)
    at System.Windows.Forms.NativeWindow.DebuggableCallba ck(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
    at System.Windows.Forms.UnsafeNativeMethods.DispatchM essageW(MSG& msg)
    at System.Windows.Forms.Application.ComponentManager. System.Windows.Forms.UnsafeNativeMethods.IMsoCompo nentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
    at System.Windows.Forms.Application.ThreadContext.Run MessageLoopInner(Int32 reason, ApplicationContext context)
    at System.Windows.Forms.Application.ThreadContext.Run MessageLoop(Int32 reason, ApplicationContext context)
    at System.Windows.Forms.Application.Run(Form mainForm)
    at TestHotBilling.Program.Main() in ..\..\Program.cs:line 17
    at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
    at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
    at Microsoft.VisualStudio.HostingProcess.HostProc.Run UsersAssembly()
    at System.Threading.ThreadHelper.ThreadStart_Context( Object state)
    at System.Threading.ExecutionContext.Run(ExecutionCon text executionContext, ContextCallback callback, Object state)
    at System.Threading.ThreadHelper.ThreadStart()
    InnerException: System.FormatException
    Message="Index (zero based) must be greater than or equal to zero and less than the size of the argument list."
    Source="mscorlib"
    StackTrace:
    at System.Text.StringBuilder.AppendFormat(IFormatProv ider provider, String format, Object[] args)
    at System.String.Format(IFormatProvider provider, String format, Object[] args)
    at System.String.Format(String format, Object arg0)
    at TestHotBilling.frmHotBilling.bgwTablUpdater_Progre ssChanged(Object sender, ProgressChangedEventArgs e) in F:\Projects\ElkaHtoBillingService\TestThread\frmTe sterMain.cs:line 602
    at System.ComponentModel.BackgroundWorker.OnProgressC hanged(ProgressChangedEventArgs e)
    at System.ComponentModel.BackgroundWorker.ProgressRep orter(Object arg)
    InnerException:


    احتمال بر ذخیره نمودن رویدادها در فایل میرود، شما چنین نمی پندارید؟ یا شاید هم سبب این باشد که ما تابع Update_dataGV را استفاده کرده (و آن نیز به نوبه خود از "رویه طلب نمودن" و به زبان باختر : InvokeMethod مستفیذ گردیده است) و سبب بروز مشکلاتی از این قسم می گردد ...
    (امیدوارم با این جمله بندی دیگه اشکال نحوی به من نگیرید : شوخی بود ها... ناراحت نشین!)

    بازم از توجهتون ممنون.

  11. #11

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    نقل قول نوشته شده توسط Saeed_m_Farid مشاهده تاپیک
    سلام، مثل همیشه آقا مهدی خشن! حالا چندان صحیح نباشه، چی میشه مگه؟ میخواستم زود با بچه ها پسرخاله بشیم، تحویلمون بگیرن ...
    سلام.
    خشونت کدومه؟

    یه سوال : نام توابعی که از ترکیب پسوندها (DoWork و RunWorkerCompleted و ...) و نام تابع اصلی درست میشن و Event Handler ها رو درست می کنند، میشه عوض بشن؟ یعنی نام تابع من یه چیز دیگه باشه : مثلاً bgwTablUpdater_DoWork بشه DoWorkTablUpdater، فکر نکنم نشه! چون من دارم دستی Event Handler رو اختصاص میدم، درسته؟
    البته که درسته. شما میتونید هر اسمی رو که مایل بودید به تابع خودتون اختصاص بدید. حتی میتونید از anonymous delegate ها استفاده کنید (که البته اینکارو نکنید).

    مشکل : یک استثناء یا بهتر اگر گویم : اعتراض (بیگانگان Exception گویند) خفن دریافت می کنیم، بدین سان : Exception has been thrown by the target of an invocation.
    و جزئیات اش مشتمل بر موارد ذیل می گردد:
    خوب. قبل از اینکه به این مساله بپردازم، اجاره بدید ابتدا یه چیز دیگه بگم. اونم اینکه قرار شد توی Worker Thread کاری با UI نداشته باشید. شما نباید توی DoWork پنجره باز کنید و ... منظورم MessageBox هستش... این کارو قبل از Start کردن Thread انجام بدید. مساله دوم گرفتن همه Exception ها توسط Catch(Exception ex) هستش. این کد، بیشتر از اونی که فکر میکنید خطرناکه، چون SEH های Windows رو هم میتونه بگیره!!! (توضیحش رو میتونید در یکی از مقالات شماره های اخیر مجله MSDN پیدا کنید).

    اما در مورد Exception ای میگیرید، خوب برای فهمیدن این موضوع، میتونید توی Exception اتون یک Breakpoint بذارید، هر وقت اجرا اونجا پرید، Call Stack رو نگاه کنید و سریع السیر به ایراد پی ببرید. به همین سادگی...

    ضمنا، لازم نیست با هر بار Click شدن Button، شما برای گرفتن Event مورد نظر، Subscribe کنید. فقط یک بار، اول کار (هنگام Load فرم، یا در CTOR) اینکارو انجام بدید... در نهایت، مطمئن بشید که هر کاری توی DoWork میکنید، ربطی به UI نداشته باشه....

    موفق باشید.

  12. #12

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    چون SEH های Windows رو هم میتونه بگیره!!! (توضیحش رو میتونید در یکی از مقالات شماره های اخیر مجله MSDN پیدا کنید).
    میشه لینکش رو بدید؟ تا جایی که من اطلاع دارم، Exceptionهای خاصی مثل Guard page exception بطور خودکار توسط مکانیزم SEH ارائه شده توسط runtime بدون اینکه catch بشند، به Execption handler سیستم عامل می رسند، تا کدهایی که هیچ شرطی برای Exceptionهای Catch شده نمیگذارند، موجب خرابکاری نشند.
    البته من از مکانیزم داخلی SEH در Runtime دات نت اطلاع دقیقی ندارم، ولی معمولا این کاری هست که انجام میشه؛ runtime یک زبان برنامه نویسی مکانیزمی برای SEH ارائه میکنه که معمولا یک wrapper به دور مکانیزم SEH در Win32 هست، و این مکانیزم داخلی SEH برخی Exceptionهای خاص رو که نباید توسط کدهای کاربر Handle بشند را فیلتر می کنه، تا به کد کاربر نرسه.

    حالا اگر لینک اون مقاله ایی که بهش اشاره کردید رو قرار بدید، احتمالا من بهتر متوجه منظور شما و چگونگی عملکر SEH در Runtime دات نت بشم.

    با تشکر


    وَ سَيَعْلَمُ الَّذِينَ ظَلَمُوا [آل محمد حقهم] أَيَّ مُنْقَلَبٍ يَنْقَلِبُونَ - الشعراء (227)
    و ظالمین [حق آل محمد (ص) ] به زودی خواهند دانست که به کدام بازگشتگاه بازخواهند گشت.

  13. #13

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    نقل قول نوشته شده توسط علی کشاورز مشاهده تاپیک
    حالا اگر لینک اون مقاله ایی که بهش اشاره کردید رو قرار بدید، احتمالا من بهتر متوجه منظور شما و چگونگی عملکر SEH در Runtime دات نت بشم. با تشکر
    سلام.
    لینک به مقاله مزبور: Handling Corrupted State Exception
    نوشته Andrew Pardoe

    موفق باشید.

  14. #14

    نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    لینک به مقاله مزبور: Handling Corrupted State Exception
    نوشته Andrew Pardoe
    مرسی، مقاله جالبی بود. این قابلیت جدیدی هم که در نسخه 4.0 دات نت برای کنترل Exceptionهای External گذاشتن، چیز جالبی هست. البته من ندیدم چندان درباره اش اطلاع رسانی بشه (من خودم هم زیاد اخبار دات نت را دنبال نمی کنم)، ولی در این حالت باید موجب سردرگمی های زیادی بشه! مثلا کاربری که یک پروژه جدید در VS 2010 ایجاد میکنه، و به خیال اینکه کدی که در بلوک finally مینویسه حتما اجرا خواهد شد، در صورت دریافت یک External Exception کاملا گیج میشه. البته خطاهایی مثل AV اونقدر که در Native Code معمول هستند، در Managed Code پیش نمیان، و شاید به همین خاطر هم چندان درباره اش اطلاع رسانی نشده؛ یا شاید هم شده، و من از اخبار دات نت زیاد مطلع نیستم.

    البته فکر کنم در دات نت هم برای External Exceptionها یک کلاس پایه واحد وجود داشته باشه، و برنامه نویس بتونه با بررسی کلاس Exception رخ داده در بلوک Except، در صورتی که Exception از این کلاس پایه مشتق شده باشه، از برنامه خارج بشه. در دلفی کلاس EExternal برای همین منظور وجود داره، و میشه کدی مثل این نوشت:
      try
    {Yout protected code}
    except
    on e: EExternal do
    Application.Terminate
    else
    begin
    {Handle exceptions which are raised within the current thread }
    end;
    end;


    در مورد کد آقای Saeed_m_Farid ایشون میتونند نام کلاس Exception رو هم به عنوان User Data به ReportProgress ارسال کنند، و اگر کلاس ارسالی مربوط به یکی از External Exceptionها بود، Thread اصلی اجرای Worker Thread رو متوقف کنه، و اجرای Process رو خاتمه بده.


    وَ سَيَعْلَمُ الَّذِينَ ظَلَمُوا [آل محمد حقهم] أَيَّ مُنْقَلَبٍ يَنْقَلِبُونَ - الشعراء (227)
    و ظالمین [حق آل محمد (ص) ] به زودی خواهند دانست که به کدام بازگشتگاه بازخواهند گشت.

  15. #15

    Question نقل قول: نحوه استفاده از BackgroundWorker برای همزمان سازی

    نقل قول نوشته شده توسط mehdi.mousavi مشاهده تاپیک
    شما میتونید توی DoWork کار زمانبر خودتون رو انجام بدید... و هر از گاهی (بسته به نیاز) Main-Thread رو از روند کار Worker Thread مطلع کنید.
    آقا مشکل من اینه که یک تابع دارم که کار پر کردن گریدم رو انچام میده.و این تابع توو لود باید باشه.
    یعنی نه اینکه حالا این تابع حتما باید توو فرم باشه ها!منظورم اینه که حتما باید توو لود فرم گریدم پر بشه.

    مشکل اینجاست که توو DoWork چی بنویسم!؟

    توضیحات دیگم اینجاس:
    http://www.barnamenevis.org/sh....php?p=1102662

برچسب های این تاپیک

قوانین ایجاد تاپیک در تالار

  • شما نمی توانید تاپیک جدید ایجاد کنید
  • شما نمی توانید به تاپیک ها پاسخ دهید
  • شما نمی توانید ضمیمه ارسال کنید
  • شما نمی توانید پاسخ هایتان را ویرایش کنید
  •