关于LOCK的问题!

supconan365 2014-11-11 09:18:17
多线程处理同一个方法,在方法里面定义了 static object sysObject = new object();
然后有一段需要同时获取数据,为了不冲突,所以使用lock
DataTable dtn = null;
lock (sysObject)
{
dtn = SQL.GetSqlData();
}
把程序布置到服务器上之后,发现还是会出现重复获取同一部分数据的情况,现在想问的是,
这会不会和服务器有两个CPU有关系?如果和CPU没有关系,那问题到底在哪里,如何解决呢?
...全文
212 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
supconan365 2014-11-11
  • 打赏
  • 举报
回复
虽然不知道问题具体出在哪里,可能是我理解错误,也可能是我代码有问题,不过还是谢谢大家的回答,多少还是会多层理解!
於黾 2014-11-11
  • 打赏
  • 举报
回复
你先把多线程执行改为单线程循环执行 看到底数据变成什么样子的
supconan365 2014-11-11
  • 打赏
  • 举报
回复
引用 16 楼 dongxinxi 的回复:
[quote=引用 4 楼 supconan365 的回复:] 我一直以为 lock 之后 当一个线程进入 lock里面执行方法的时候 其他线程会等待 直到某个线程执行完lock里面的方法出来之后 其他线程才能进入,原来不是这样理解的? 也就是说 如果我有3个线程 那3个线程都会同时进入到lock里面执行方法吗?
跟CPU没有关系,不要把软件与硬件搞混杂了 你的程序是基于CLR(CLR基于操作系统)运行的,底层的指令集由操作系统负责 lock块的同步(阻塞)与你lock的东西有关 static object sysObject = new object(); lock(sysObject )一般用于静态方法中的线程同步:类的所有实例在多线程中执行这个lock块时都将串行执行,也就是你上面理解的,后执行的都将等待先获取锁的执行完 lock(实例对象)则仅针对这一个实例在多个线程中同步执行这个lock块[/quote] 可能我还不能完全理解你的意思,你能帮我看下 我这里的代码到底问题出现在哪里吗? 这是一个简单的控制台的程序 ,我就贴一些主要代码了。 program里面就是生成了几个线程 ThreadClass[] SubThread = new ThreadClass[ThreadNum]; for (int i = 0; i < ThreadNum; i++) { if (SubThread[i] == null) { SubThread[i] = new ThreadClass(); SubThread[i].index = i; SubThread[i].threadname = "线程:" + i.ToString(); SubThread[i].threads = new Thread(new ThreadStart(SubThread[i].SubmitNote)); SubThread[i].threads.IsBackground = true; Helper.ShowMessage("线程:" + i.ToString() + "启动......"); SubThread[i].threads.Start(); } } 然后 ThreadClass类里面就是执行的方法 static object SysObject = new object(); public void SubmitNote() { while (true) { try { DataTable dtn = null; lock (SysObject) { dtn = SQL.GetSqlData();//这里就是执行获取表最前的10条数据,然后更改标识FLAG=1,那其他线程按照条件Flag=0 就不会获取到刚才的数据了。可现在这里好像线程会获取重复记录,不知道问题到底在哪里? } 以下是一些数据操作! } catch{} } }
  • 打赏
  • 举报
回复
引用 4 楼 supconan365 的回复:
我一直以为 lock 之后 当一个线程进入 lock里面执行方法的时候 其他线程会等待 直到某个线程执行完lock里面的方法出来之后 其他线程才能进入,原来不是这样理解的? 也就是说 如果我有3个线程 那3个线程都会同时进入到lock里面执行方法吗?
跟CPU没有关系,不要把软件与硬件搞混杂了 你的程序是基于CLR(CLR基于操作系统)运行的,底层的指令集由操作系统负责 lock块的同步(阻塞)与你lock的东西有关 static object sysObject = new object(); lock(sysObject )一般用于静态方法中的线程同步:类的所有实例在多线程中执行这个lock块时都将串行执行,也就是你上面理解的,后执行的都将等待先获取锁的执行完 lock(实例对象)则仅针对这一个实例在多个线程中同步执行这个lock块
supconan365 2014-11-11
  • 打赏
  • 举报
回复
引用 13 楼 hbu_pig 的回复:
lock (sysObject) { dtn = SQL.GetSqlData(); ... ... } lock只能保证大括号里面的语句在同一时刻只有一个线程在操作。
我也就是这样想的啊,大括号里的方法就是获取记录 然后更新标识的! 按照道理 大括号里的数据更新之后,其他线程是不可能获取相同的记录了,可是现在还是会出现相同的记录,就是这点想不明白啊!
supconan365 2014-11-11
  • 打赏
  • 举报
回复
引用 11 楼 sp1234 的回复:
在你的 dtn = SQL.GetSqlData(); 前后写两天“记录日志”语句,例如写
File.WriteAllText(file, string.Format("{0} 开始 {1}\r\n", DateTime.Now, this.GetHash());
....
File.WriteAllText(file, string.Format("{0} 结束 {1}\r\n", DateTime.Now, this.GetHash());
然后看看执行次序和时间,是不是真的“多个任务同时执行”了?!
我把获取出来的唯一ID记录下来了,是有重复的记录!
欢乐的小猪 2014-11-11
  • 打赏
  • 举报
回复
lock (sysObject) { dtn = SQL.GetSqlData(); ... ... } lock只能保证大括号里面的语句在同一时刻只有一个线程在操作。
烈火蜓蜻 2014-11-11
  • 打赏
  • 举报
回复
要是觉的,关于在于你的访问数据库的方法,取完之后有没有马上更新状态,没有话,取到一样数据是正常,
  • 打赏
  • 举报
回复
在你的 dtn = SQL.GetSqlData(); 前后写两天“记录日志”语句,例如写
File.WriteAllText(file, string.Format("{0} 开始 {1}\r\n", DateTime.Now, this.GetHash());
....
File.WriteAllText(file, string.Format("{0} 结束 {1}\r\n", DateTime.Now, this.GetHash());
然后看看执行次序和时间,是不是真的“多个任务同时执行”了?!
supconan365 2014-11-11
  • 打赏
  • 举报
回复
引用 9 楼 Z65443344 的回复:
你想多线程同时访问数据库的不同数据,是为了提高访问效率,那就不应该使用lock,否则跟单线程循环访问数据库有任何区别吗 还是先理清逻辑,再谈代码该如何编写
我就想实现多线程访问数据的时候能不会获取相同的数据出来,我一开始以为lock是锁定之后会让其他线程等待,这样就不会出现获取相同数据了,可是现在我知道我的想法错误了,所以才在这里请教你们的啊! 那我现在多线程获取的数据肯定用的是同一个方法 而当获取数据之后 我会改变里面的标识 但现在的问题是 多线程访问的时候 一个线程还没有修改获取数据标识的时候 另一个线程倒是又进去获取了 这样就会出现重复了,就是想请教 这种问题该如何处理最好?
於黾 2014-11-11
  • 打赏
  • 举报
回复
你想多线程同时访问数据库的不同数据,是为了提高访问效率,那就不应该使用lock,否则跟单线程循环访问数据库有任何区别吗 还是先理清逻辑,再谈代码该如何编写
supconan365 2014-11-11
  • 打赏
  • 举报
回复
引用 3 楼 Z65443344 的回复:
而且目测你这是在访问数据库 访问数据库,多线程可以同时访问,不会冲突,可以不用加锁 而取出的数据一样,如果你的SQL语句是一样的,取出的数据当然也是一样的 不管你是2个线程同时访问数据库,还是按顺序访问,都不应该出现数据不一致
因为我是想获取一张表的数据,比如A表有10条数据,我一个线程获取5条的时候,当获取的数据的标识没有来得及修改成已获取,那第二个线程也进去获取了,那这样就会出现相同的数据了啊,那这种情况能不能锁定一个线程进去访问的时候 另一个线程只能等待呢,这样该如何处理呢?
於黾 2014-11-11
  • 打赏
  • 举报
回复
比如我有这样一个函数: int f(int i) { return i; } 那么多线程同时执行这个函数,而传入的参数各不相同,那么即使并发执行,返回的值也是各不相同的. 再看另一个函数: int f() { return 1; } 不管是并发执行还是循环顺序执行,返回的都是1,跟并发不并发没有任何关系.
於黾 2014-11-11
  • 打赏
  • 举报
回复
并发执行,也有可能获取到不一样的数据,顺序执行,也可能获取到一样的数据,具体看你处理逻辑
於黾 2014-11-11
  • 打赏
  • 举报
回复
引用 4 楼 supconan365 的回复:
我一直以为 lock 之后 当一个线程进入 lock里面执行方法的时候 其他线程会等待 直到某个线程执行完lock里面的方法出来之后 其他线程才能进入,原来不是这样理解的? 也就是说 如果我有3个线程 那3个线程都会同时进入到lock里面执行方法吗?
你理解的没有问题 lock的作用就是把并发执行变成了顺序执行,其他线程执行到这里会阻塞住 不过这跟你获取到的数据一样不一样没有任何关系
supconan365 2014-11-11
  • 打赏
  • 举报
回复
引用 1 楼 Z65443344 的回复:
是否获取同一部分数据,是你的业务逻辑的问题,跟加不加lock没有关系 加lock是为了解决多线程同时操作同一个对象造成的线程安全问题 比如其中一个线程在对list进行遍历操作,而另一个线程却要add或remove,那就会引起冲突,导致抛异常 而两个线程取出的数据相同,检查一下你两个线程使用的参数是否是一样的吧 如果传入的参数一样,返回的结果也必然是一样的
我一直以为 lock 之后 当一个线程进入 lock里面执行方法的时候 其他线程会等待 直到某个线程执行完lock里面的方法出来之后 其他线程才能进入,原来不是这样理解的? 也就是说 如果我有3个线程 那3个线程都会同时进入到lock里面执行方法吗?
於黾 2014-11-11
  • 打赏
  • 举报
回复
而且目测你这是在访问数据库 访问数据库,多线程可以同时访问,不会冲突,可以不用加锁 而取出的数据一样,如果你的SQL语句是一样的,取出的数据当然也是一样的 不管你是2个线程同时访问数据库,还是按顺序访问,都不应该出现数据不一致
xdashewan 2014-11-11
  • 打赏
  • 举报
回复
还得看你GetSqlData是如何操作的,线程虽然lock了,但你条件相同取到相同数据的可能性还是存在
於黾 2014-11-11
  • 打赏
  • 举报
回复
是否获取同一部分数据,是你的业务逻辑的问题,跟加不加lock没有关系 加lock是为了解决多线程同时操作同一个对象造成的线程安全问题 比如其中一个线程在对list进行遍历操作,而另一个线程却要add或remove,那就会引起冲突,导致抛异常 而两个线程取出的数据相同,检查一下你两个线程使用的参数是否是一样的吧 如果传入的参数一样,返回的结果也必然是一样的
心雨蒙蒙 2014-11-11
  • 打赏
  • 举报
回复
using System.Threading; static object sysObject = new object(); 换成 static AutoResetEvent myResetEvent = new AutoResetEvent(true); lock (sysObject) { dtn = SQL.GetSqlData(); } 换成 myResetEvent.WaitOne(); dtn = SQL.GetSqlData(); myResetEvent.Set(); 小弟也是初学者,请问各位大神这样可不可以呢?

110,539

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧