Jaimesh
Jaimesh

Reputation: 851

Share Single Datatable in Multi Threading in C#

I have an application, which have three threads. which access single datatable. Each thread print one row at single time. It should not repeat.but In my application all three threads are print all row from datatable.

I want that one row should print only once.

   class Program
    {
        static void Main(string[] args)
        {
            ThreadStart testThread1Start = new ThreadStart(new program().testThread1);
            ThreadStart testThread2Start = new ThreadStart(new Program().testThread2);

            Thread[] testThread = new Thread[2];
            testThread[0] = new Thread(testThread1Start);
            testThread[1] = new Thread(testThread2Start);

            foreach (Thread myThread in testThread)
            {
                myThread.Start();
            }
            Console.ReadLine();
        }

        private void testThread2()
        {          
            DataTable dt = SQLite.ExecuteQuery("SELECT id,name,address FROM example ");
            if (dt.Rows.Count != 0)
            {            
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    lock (dt.Rows[i])
                    {
                        var Id = dt.Rows[i]["Id"].ToString();
                        SQLite.ExecuteNonQuery("update example set DisplayDataStatus = 1 where id= '" + Id + "' ");
                        var name = dt.Rows[i]["name"].ToString();
                        var address = dt.Rows[i]["address"].ToString();
                        Console.WriteLine("ID:"+Id+"|Name:"+name+"|address:"+adress);
                    }
                    Console.ReadLine();
                }
            }
            else
            {}
        }

        private void testThread1()
        {
            DataTable dt = SQLite.ExecuteQuery("SELECT id,name,address FROM example ");
            if (dt.Rows.Count != 0)
            {            
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    lock (dt.Rows[i])
                    {
                        var Id = dt.Rows[i]["Id"].ToString();
                        SQLite.ExecuteNonQuery("update example set DisplayDataStatus = 1 where id= '" + Id + "' ");
                        var name = dt.Rows[i]["name"].ToString();
                        var address = dt.Rows[i]["address"].ToString();
                        Console.WriteLine("ID:"+Id+"|Name:"+name+"|address:"+adress);
                    }
                    Console.ReadLine();
                }
            }
            else
            {}
        }
    }

Upvotes: 0

Views: 3571

Answers (1)

Massimiliano Kraus
Massimiliano Kraus

Reputation: 3833

FIRST

Why are you re-executing the "SQLite.ExecuteQuery" in every single thread? If you only want to print all the rows in the table without blocking UI, it's enough to have a single background Thread that executes the query and then prints the rows. Having more threads that try to read from the same database and try to write to the same Console, can slow down your application instead of speeding it up (because the time of execution is the same but you have to sum the time required for all the context-switches between threads).

SECOND

Ok, suppose you still need 3 threads to execute other parallel operations.

Suppose the DataTable instance is the same for all threads. The lock on the Row is only blocking the threads from writing that Row at the same time. Suppose Thread T1 is writing Row R1. T2 is blocked on R1 and cannot write it. Then T1 finishes, unblocks R1 and blocks R2. Because R1 is now unblocked, T2 enters the lock section of R1 and write R1. And so on. So all the threads write all the rows, but at different moments.

Suppose instead that every Thread creates its own DataTable, as your code does. If T1 locks on dt.Row[0], that's not the same object as dt.Row[0] of T2! They're separate objects, so a lock section won't block the execution of any other thread!

THIRD

The "if (dt.Rows.Count != 0)" statement is completely useless. When you enter the for loop, and there are no rows, the loop exits at the first check without consequences.

A check that makes sense before a for/foreach loop is the one against null list. So you can write:

"if (Rows != null) { for (int i = 0; i < Rows.Count; i++) { ... ... ... }"

UPDATE

If you only have to print the rows to the Console, you can have 1000 threads, but since they all print to the same single Console, you have 999 useless threads. The situation is different if you have to perform some "expensive" operation on a row and then display it to the Console. In this case, try this:

  • Execute a query that retrieves only the Rows count.
  • Divide all the rows in three ranges based on the total count, assign one range to each thread and start each thread. For example, T1 execute the query only for the rows 0-14999, T2 executes for 15000-29999, and so on.
  • The method passed to each thread can be the same, but with different input startRow and endRow numbers. The method creates a DataTable only with those rows and print only those rows to the Console.

This solution doesn't print the rows all in order, anyway. Is that a requirement?

Upvotes: 1

Related Questions