勇哥注:
我们继续上一篇《C# 勇哥关于多线程读写plc内存的研究续,引用ReaderWriterLockSlim锁带来的读操作并发的问题》
此系列贴子已经写了好几篇了:
(4)C# 勇哥关于多线程读写plc内存的研究续,引用ReaderWriterLockSlim锁带来的读操作并发的问题
http://www.skcircle.com/?id=1995
(3)C# 勇哥关于多线程读写plc内存的研究续,解决UI控件读写的效率问题
http://www.skcircle.com/?id=1985
(2)C# 勇哥关于多线程读写plc内存的研究续,解决lock锁的效率问题
http://www.skcircle.com/?id=1983
(1) C# 勇哥关于多线程读写plc内存的研究
http://www.skcircle.com/?id=1981
上一篇末尾的问题:
跑了一晚上后,发现只有最后一个地址的数值(13414)在跳动,其它的都不动,应该是死掉了。

首先勇哥检查了plc的内存,发现头三个地址的值确实没有更新了,只有最后一个地址的值在变化。
这说明“启动4个读线程”没有问题,并不是因为它们死掉了所以ui上刷新不了。
再看下其中一个写线程的代码:
PlcReadWrite plc = null;
Random ran = null;
Task.Factory.StartNew(() =>
{
Stopwatch sw1 = new Stopwatch(); sw1.Start();
short j1 = 0;
while (!rndStop)
{
plc = new PlcReadWrite();
++j1;
plc.Write(0,j1, Guid.NewGuid());
while(true)
{
if(sw1.ElapsedMilliseconds>1000)
{
sw1.Restart();break;
}
Thread.Sleep(10);
}
}
});首先那个j1是个short,最大值为32767,所以并不是因为j1溢出了。
由数值6717来看,第一个地址写内存是每隔1秒写一次,也就不到2小时,上面的代码就死掉再不工作了。
地址1--地址4,依次是隔1, 2, 3, 4秒写入
但是最后一个地址值反而最大,这让人怀疑是否写入混乱了。
我们干脆加把锁,让4个写入无可能同时写入。(虽然4个时序按时序来讲好像是不能同时写入的)
这个锁定义如下:
private static readonly object writeLock = new object();
只需要lock到Write函数里就行了。
现在这个函数就有两把锁了。
/// <summary>
/// 写plc内存
/// </summary>
/// <param name="addr">plc内存地址,填写相对地址,从0开始</param>
/// <param name="data">写入的数据,short类型</param>
/// <param name="_id">guid</param>
/// <returns></returns>
public int Write(int addr,short data, Guid _id)
{
lock (writeLock)
{
rwlock.EnterWriteLock();
{
try
{
var writeSw = new Stopwatch();
writeSw.Start();
isRead = false;
WriteCmdList.Add(new WriteCmd()
{
addr = addr,
id = _id,
writeData = data,
writeStatus = -1
});
var idx = -1;
int js1 = 0;
while (true)
{
if (writeSw.ElapsedMilliseconds > 2000)
{
//读plc超时
writeSw.Stop(); return -1;
}
if (sw2.ElapsedMilliseconds > 50 && js1 == 0)
{
//通知写plc
mr[0].Set(); sw2.Restart(); ++js1;
}
idx = WriteCmdList.FindIndex(s => s.id == _id && s.writeStatus == 1);
if (idx >= 0)
{
//写成功了,返回1
WriteCmdList.RemoveAt(idx);
plclog.AddLog(new logdata()
{
id = _id,
readOrWrite = readwriteEnum.write,
plcAddr = (short)addr,
recTime = DateTime.Now,
itemCount = WriteCmdList.Count
});
return 1;
}
Thread.Sleep(1);
}
}
finally
{
rwlock.ExitWriteLock();
}
}
}
}由于至少要测试2小时以上才可能看到结果。
就留今天晚上跑通宵吧。
未完待续。。。。
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!


少有人走的路

















