Search code examples
c#multithreadingthread-safetysimultaneous-calls

c# multi threading with simultaneous access on a listbox > data lost (pick/remove)


I have a ListBox with a list of URLs.

I have 2 threads taking theses URLs and treat them into a function.

My Thread 1 takes the items[0] of the ListBox, and my Thread 2 takes the items[1].

After the Thread picked up the item, it immediately remove it using Items.RemoveAt(0 or 1)

My problem using this method is that some of the URL are treated twice, some even not.

Isnt there a way to flag an URL or something else ? I'm not so familiar with multi threading

PS: In my example i said i was using 2 threads, in reality i use 5 threads.

Thanks in advance

EDIT : Used the concurentqueue system :

    Thread th1;
    Thread th2;
    Thread th3;
    Thread th4;
    Thread th5;
    ConcurrentQueue<string> myQueue= new ConcurrentQueue<string>();
    Int queueCount = 0;

    private void button2_Click(object sender, EventArgs e)
    {
    //initialize objects and query the database
        DBconnect conn;
        conn = new DBconnect();
        string query = "SELECT Url FROM Pages WHERE hash = ''";
        List<string> result = conn.Select(query);
        for (int i = 0; i < result.Count(); i++)
        {
    //For all rows found, add them to the queue
            myQueue.Enqueue(result[i]);
        }
    //start the 5 threads to process the queue              
        th1 = new Thread(ProcessTorrent);
        th2 = new Thread(ProcessTorrent);
        th3 = new Thread(ProcessTorrent);
        th4 = new Thread(ProcessTorrent);
        th5 = new Thread(ProcessTorrent);
        th1.Start();
        th2.Start();
        th3.Start();
        th4.Start();
        th5.Start();

    }


    private void ProcessTorrent()
    {
    //Start an unlimted task with continueWith
        Task tasks = Task.Factory.StartNew(() =>
        {
    //Check if there are still items in the queue
            if (myQueue.Count > 0)
            {
                string queueURL;
                bool haveElement = myQueue.TryDequeue(out queueURL);
        //check if i can get an element from the queue
                if (haveElement)
                {
        //start function to parse the URL and increment the number of items treated from the queue
                    get_torrent_detail(queueElement);
                    Interlocked.Increment(ref queueCount);
                    this.Invoke(new Action(() => label_total.Text = (myQueue.Count() - queueCount).ToString()));

                }
            }
        });
    //continue the task for another queue item
        tasks.ContinueWith(task =>
        {
            ProcessTorrent();
        });
    }

Solution

  • It sounds like you're using a UI control to coordinate tasks between multiple threads.

    That is an extremely bad idea.

    Instead, you should queue up the tasks into a ConcurrentQueue<T> or BlockingCollection<T>, and have other threads take items from the queue and process them.