多进程用户并发处理Demo(C#版)

这个示例主要演示的是在多进程操作数据库时,如何避免并发重复数据入库的例子。

过多的线程理论不再阐述,网上、书上皆有。

项目采用 Asp.Net Framework 4.5 / Mysql 5.4 数据库。

 

首先创建一个 LockInsertDB.cs 文件,这个文件用来实现数据库添加; 

 1  using System;
 2  using MySql;
 3  using MySql.Data.MySqlClient;
 4  using System.Collections.Generic;
 5  using System.Linq;
 6  using System.Text;
 7  using System.Threading.Tasks;
 8 
 9  namespace DBImportTool
10 {
11      public  class LockInsertDB : Common
12     {
13          private  object obj =  new  object();
14          ///   <summary>
15           ///  添加测试数据
16           ///   </summary>
17           ///   <param name="path"> 字段内容 </param>
18           ///   <param name="tname"> 线程名称 </param>
19           public  void InsertTestDB( string path,  object tname)
20         {
21             MySql.Data.MySqlClient.MySqlConnection conn =  new MySql.Data.MySqlClient.MySqlConnection( " Server=10.17.1.57; Database=videodb; Uid=root; Pwd=xingzhi ");
22              try
23             {
24                 conn.Open(); // 打开连接
25                  MySql.Data.MySqlClient.MySqlCommand cmd =  new MySql.Data.MySqlClient.MySqlCommand();
26                 cmd.Connection = conn;
27                  // 加入多线程,排它锁机制.
28                   lock (obj)
29                 {
30                      string  select =  " SELECT * FROM `tbl_test` WHERE `filepath` = ' " + path +  " ' ";
31                     cmd.CommandText =  select;
32                      object val = cmd.ExecuteScalar();
33                      if (val ==  null)
34                     {
35                          string sql =  " INSERT INTO `tbl_test` (`filepath`, `addtime`) VALUES (' " + path +  " ', NOW()); ";
36                         cmd.CommandText = sql;
37                         cmd.ExecuteNonQuery();
38                         P(DateTime.Now.ToString() +  " \t " + tname +  " \tOK\t " + path +  " \n ");
39                     }
40                      else
41                     {
42                         P(DateTime.Now.ToString() +  " \t " + tname +  " \t已存在\t " + path +  " \n ");
43                     }
44                 }
45             }
46              catch
47             {
48 
49             }
50              finally
51             {
52                  // 关闭连接
53                  conn.Close();
54             }
55         }
56          ///   <summary>
57           ///  测试输出
58           ///   </summary>
59           ///   <param name="str"> 输出内容字符串 </param>
60           public  void P( string str)
61         {
62             Console.Write(str);
63         }
64     }

65 } 

 

再创建一个控制台工程,Main方法代码如下:

 1  using System;
 2  using System.Threading;
 3  using System.IO;
 4  using System.Collections.Generic;
 5  using System.Linq;
 6  using System.Text;
 7  using System.Threading.Tasks;
 8  namespace DBImportTool
 9 {
10      public  class Mcqueen
11     {
12          static  void Main( string[] args)
13         {
14             Run();
15             Console.ReadLine();
16         }
17          ///   <summary>
18           ///  进程数量.
19           ///   </summary>
20           static  int tnum =  2;
21          ///   <summary>
22           ///  所对象
23           ///   </summary>
24           static  object obj =  new  object();
25          ///   <summary>
26           ///  线程数组.
27           ///   </summary>
28           static Thread[] threadarr =  new Thread[tnum];
29          ///   <summary>
30           ///  数据库插入对象.
31           ///   </summary>
32           static LockInsertDB mdb =  new LockInsertDB();
33          ///   <summary>
34           ///  运行函数
35           ///   </summary>
36           public  static  void Run()
37         {
38              for ( int i =  0; i < tnum; i++)
39             {
40                 Thread t =  new Thread(T1);
41                 threadarr[i] = t;
42                 threadarr[i].Name =  " Thread  " + i.ToString() +  "  : ";
43             }
44              int y =  0;
45              while (y < tnum)
46             {
47                 threadarr[y].Start(threadarr[y].Name);
48                 y++;
49             }
50         }
51          ///   <summary>
52           ///  读取磁盘文件路径.
53           ///   </summary>
54           ///   <param name="tname"> 线程名称 </param>
55           public  static  void T1( object tname)
56         {
57             DirectoryInfo di = Directory.CreateDirectory( @" F:\邢智的文件\ ");
58             GetFiles(di, tname);
59         }
60          ///   <summary>
61           ///  采用对列入栈模式对列遍历文件夹结构.
62           ///   </summary>
63           ///   <param name="di"> 目录对象 </param>
64           ///   <param name="tobj"> 线程名称 </param>
65           private  static  void GetFiles(DirectoryInfo di, object tobj)
66         {
67              int sgin =  1;
68             Stack<DirectoryInfo> stack_dir =  new Stack<DirectoryInfo>();
69             DirectoryInfo dir = di;
70             stack_dir.Push(di);
71              while (stack_dir.Count !=  0)
72             {
73                 dir = stack_dir.Pop();
74                 DirectoryInfo[] diarr = dir.GetDirectories();
75                  foreach (DirectoryInfo d  in diarr)
76                     stack_dir.Push(d);
77                 FileInfo[] files = dir.GetFiles();
78                  foreach (FileInfo f  in files)
79                 {
80                     mdb.InsertTestDB(f.FullName.Replace( " \\ "" \\\\ "), tobj);
81                     Thread.Sleep( 200);
82                     sgin++;
83                 }
84             }
85         }
86          public  static  void P( string str)
87         {
88             Console.Write(str);
89         }
90     }

91 } 


static LockInsertDB mdb = new LockInsertDB();

一开始把这句初始化对象放到了private static void GetFiles(DirectoryInfo di,object tobj) 函数里面,虽然在后续的执行过程中没有任何问题,

但是初始化运行线程时导致了进程并发进入lock锁中,后来研究一下原因,是因为每个进程都在实例化化它的时候都会在lock中分配一个标识符,

这样一来,假如A进程内实例化了A1,那么当B进程进来之后,B却不认识A线程内的A1,因此lock也就对A1不起作用了。

因此把这个类跳出线程而放到一个全局中去实例化,也就不存在这个lock失效的问题了。

 

运行结果如下: 

 

如果需要模拟更多的进程用户,只需要把 tnum = 2 的数值改一下即可。 

转载于:https://www.cnblogs.com/mcqueen/p/4024946.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值