728x90 AdSpace

  • Latest News

    [Tips] How to fix Cross-thread problem with C# control (2/2)

    Today I'll show you how to fix cross-thread problem with the second way. This way is used with Invoke and BeginInvoke API. What is Invoke and BeginInvoke? let's read below topics

    First Let's understanding the synchronous and asynchronous read here

    What is Synchronous and Asynchronous

    Synchronous

    Synchrouous and Asynchronous

    Example:
    1. You are in a queue to get a movie ticket. You cannot get one until everybody in front of you gets one and the same applies to the people queued behind you
    2. Ammunition in the gun: shot every ammunition one by one

    Asynchronous


    Synchrouous and Asynchronous

    Example:
    1. You are in restaurant with many other people. You order your food. Other people can also order their food. They don’t have to wait for your food to be cooked and served to you before they can order. In the kitchen, workers are continuously cooking, serving and taking orders. People will get their food servered as soon as it is cooked
    2. About car traffic: the car can pass another car, no need to waiting the before car







    Resource contention

    - when running a application, the main is created, that's call main-thread. if this have many thread doing the multi-task and the thread need use the resource from the main thread, if you try to access  resource from the main thread, you can get resource contention problem

    - The Invoke is appeared at this time to help you lock the resource guaranteed the thread-safe and don't make the problem is crashed by resource contention!


    - Khi chạy một ứng dụng, có một thread được tạo ra để chạy hàm Main(). Đó là thread chính (main-thread). Nếu chương trình có nhiều thread thực hiện các tác vụ xử lý khác và các thread này cần sử dụng tài nguyên từ thread chính thì bạn phải cần tới Invoke. Thực ra, bạn có thể đặt thuộc tính CheckForIllegalCrossThreadCalls = false; cho form (hoặc control) và sử dụng các tài nguyên từ thread khác một cách thoải mái. Nhưng như vậy, chương trình sẽ rơi vào trạng thái ko an toàn (unsafe) và sẽ bị crash bất cứ lúc nào khi các thread tranh chấp tài nguyên với nhau.

    - C# cung cấp 1 giải pháp an toàn hơn đó là Invoke. Khi bạn gọi phương thức này của một form (hoặc control) từ 1 thread khác, form (control) đó sẽ bị lock, chỉ cho phép thread đã gọi nó truy cập. Khi thread này hoàn thành tác vụ của nó, form (control) lại được giải phóng cho thread khác gọi. Như vậy, các thread sẽ được đồng bộ với nhau và chương trình của bạn sẽ ko bị crash. Đó gọi là thread-safe.

    - Có những control ko yêu cầu Invoke để thực hiện thread-safe. Nghĩa là nó có thể được truy cập một cách trực tiếp không qua Invoke. Thuộc tính InvokeRequired sẽ cho biết một control có yêu cầu Invoke khi gọi hay không?


    BeginInvoke and Invoke

    BeginInvoke() will schedule the asynchronous action on the GUI thread. When the asynchronous action is scheduled, your code continues. Some time later (you don't know exactly when) your asynchronous action will be executed

    Invoke() will execute your asynchronous action (on the GUI thread) and wait until your action has completed. -> easy get deadlock but safe than BeginInvoke

    Look at the below example:

    Source code

    Main.cs


    private bool isProcessRunning = false;
    private void Demo(object sender, EventArgs e)
    {
    listBox1.Items.Clear();

    // If a process is already running, warn the user and cancel the operation
    if (isProcessRunning)
    {
    MessageBox.Show("A process is already running.");
    return;
    }

    // Initialize the thread that will handle the background process
    Thread backgroundThread = new Thread(new ThreadStart(() => CallingThread()));

    // Start the background process thread
    backgroundThread.Start();
    }



    1st Example: 

    single code: 
    listBox1.Invoke(new Action(() => listBox1.Items.Add(lst[i])));

    multi code: use { and }
    listBox1.BeginInvoke(new Action(() =>
    {
         listBox1.Items.Add(lst[i]))
    });

    We use Invoke in this case because we want to wait until the user action has completed.


    // Developer: zidane / VịLH (huuvi168@gmail.com)
    // Last modified: 2016-07-07
    private void CallingThread()
    {
    toolStripProgressBar.ProgressBar.Invoke(new Action(() =>
    toolStripProgressBar.Style = ProgressBarStyle.Marquee));

    toolStripStatusLabel.Text = "Waiting for task ...";

    // Set the flag that indicates if a process is currently running
    isProcessRunning = true;

    clsDBConnect clsDB = new clsDBConnect();
    List<string> lst = clsDB.SelectQueryString();

    // Thread.sleep(100); // remember set Thread.Sleep(1000) here

    for (int i = 0; i < lst.Count; i++)
    {
    if (listBox1.InvokeRequired)
    listBox1.Invoke(new Action(() => listBox1.Items.Add(lst[i])));
    }

    // Show a dialog box that confirms the process has completed
    toolStripStatusLabel.Text = "Done";

    // Reset the progress bar's value if it is still valid to do so
    toolStripProgressBar.ProgressBar.Invoke(new Action(() =>
    toolStripProgressBar.Style = ProgressBarStyle.Continuous));

    // Reset the flag that indicates if a process is currently running
    isProcessRunning = false;

    }


    2nd Example: 

    listBox1.BeginInvoke(new Action(() => listBox1.Items.Add(lst[i])));

    Shouldn't use beginInvoke in this case, because it will crashed your program.


    private void CallingThread()
    {
    toolStripProgressBar.ProgressBar.Invoke(new Action(() =>
    toolStripProgressBar.Style = ProgressBarStyle.Marquee));

    toolStripStatusLabel.Text = "Waiting for task ...";

    // Set the flag that indicates if a process is currently running
    isProcessRunning = true;

    clsDBConnect clsDB = new clsDBConnect();
    List<string> lst = clsDB.SelectQueryString();

    for (int i = 0; i < lst.Count; i++)
    {
    if (listBox1.InvokeRequired)
    listBox1.BeginInvoke(new Action(() => listBox1.Items.Add(lst[i])));
    }

    // Show a dialog box that confirms the process has completed
    toolStripStatusLabel.Text = "Done";

    // Reset the progress bar's value if it is still valid to do so
    toolStripProgressBar.ProgressBar.Invoke(new Action(() =>
    toolStripProgressBar.Style = ProgressBarStyle.Continuous));

    // Reset the flag that indicates if a process is currently running
    isProcessRunning = false;

    }




    Relative topic
    http://learn-tech-tips.blogspot.com/2015/11/how-to-fix-cross-thread-problem-CSharp.html 

    If you have any feedback, leave your comment, we can discuss about it!
    Have a nice day!
    Zidane
    https://learn-tech-tips.blogspot.com/

    • Blogger Comments
    • Facebook Comments

    1 comments:

    1. Did you know that you can make money by locking selected sections of your blog / site?
      All you need to do is to join AdscendMedia and use their Content Locking plugin.

      ReplyDelete

    Item Reviewed: [Tips] How to fix Cross-thread problem with C# control (2/2) Rating: 5 Reviewed By: Unknown
    Scroll to Top