在C#中以多线程共享单个数据表

时间:2016-03-31 11:13:20

标签: multithreading locking shared-memory

我有一个应用程序,它有三个线程。哪个访问单个数据表。 每个线程一次打印一行。它不应该重复。但在我的应用程序中,所有三个线程都打印出来自datatable的所有行。

我希望一行只打印一次。

   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
            {}
        }
    }

1 个答案:

答案 0 :(得分:1)

<强>第一

为什么要在每个线程中重新执行“SQLite.ExecuteQuery”?如果您只想在不阻止UI的情况下打印表中的所有行,则只需要一个单个后台Thread来执行查询,然后打印行。 有更多的线程试图从相同的数据库读取并尝试写入相同的 Console,可能会降低应用程序的速度而不是加快速度(因为执行的时间是相同的,但你必须总结线程之间所有上下文切换所需的时间。)

<强> SECOND

好的,假设您仍需要3个线程来执行其他并行操作。

假设所有线程的DataTable实例都相同。 Row上的锁定仅阻止线程同时写入Row 。假设Thread T1正在编写Row R1。 T2在R1上被阻止,无法写入。然后T1完成,解锁R1并阻止R2。由于R1现在未被阻塞,因此T2进入R1的lock部分并写入R1。等等。所以所有的线程都会写出所有的行,但是在不同的时刻。

相反,假设每个Thread都会创建自己的DataTable,就像您的代码一样。如果T1在dt.Row[0]上锁定,那与T2的dt.Row[0]不同!它们是单独的对象,因此锁定部分不会阻止任何其他线程的执行!

<强> THIRD

if (dt.Rows.Count != 0)”语句完全没用。 当您输入for循环,并且没有行时,循环会在第一次检查时退出而没有后果。

在for / foreach循环之前有意义的检查是针对空列表的检查。所以你可以写:

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

<强>更新

如果您只需要将行打印到控制台,则可以有1000个线程,但由于它们都打印到同一个控制台,因此您有999个无用的线程。如果您必须在一行上执行某些“昂贵”操作并且然后将其显示到控制台,则情况会有所不同。在这种情况下,试试这个:

  • 执行仅检索行计数的查询。
  • 根据总计数划分三个范围内的所有行,为每个线程分配一个范围并启动每个线程。例如,T1仅针对行0-14999执行查询,T2针对15000-29999执行查询,依此类推。
  • 传递给每个线程的方法可以相同,但使用不同的输入startRowendRow数字。该方法仅使用这些行创建DataTable,并仅将这些行打印到控制台。

无论如何,此解决方案不会按顺序打印所有行。这是一项要求吗?