线程池的线程仿佛用完了
线程池的线程好像用完了
我的程序是用tcpclient与几十台下位机通讯。在论坛大神的帮助下,程序写成了这个样子。
现在的问题是,程序运行一个多小时后,通讯就会中断,断点发现这时候程序根本就不执行ThreadPollCallback,而且整个程序变得非常慢,感觉就像是线程池已经用完了,再有新的线程也不理会一样。
我猜想可能与tcp连接失败有关。
因为下位机中经常有一些没有连到网络,所以有一些线程是在不断重复“connect,失败”的过程。看上去这个过程每秒都要新开一个线程来做,而且旧的线程并不会被回收。
求助,这个问题怎么办啊?
------解决思路----------------------
就你这一句话,就知道你的线程池为啥满了……
你为啥要开新线程去判断是否能通讯呢?为什么不能再fail后再此线程内继续连接呢?
------解决思路----------------------
设置超时时间啊,超时了还没有回复,就别等了
我多次用收快递来打比方.
你从网上订购东西,就相当于是发送请求
你要接收数据,就好比是等快递.
等快递有很多种办法,
1.异步的方式就是快递来了放门卫,门卫给你打电话,然后你去取.
当然快递一直不来,门卫就一直不给你打电话,你需要自己设置个定时器,判断时间太长了怎么还没到,然后自己打电话去催.
2.同步的方式就是你订货之后,就没事去门卫那里溜达溜达,看看货到是没到.
而你现在就是用同步的思想来做.
同步的思想再加上线程池的概念,就是你自己不去看,而是派个人去看.
而你没告诉派去的人要等多长时间还不来就回来,而是没来就一直在那里等.
然后你又在时间过长之后,又派新的人去看.
导致门卫那里堵了一大堆人都在帮你等快递,这有任何意义??
------解决思路----------------------
设置ReceiveTimeout之后,如果超时了还没有数据到达,就会报个错误,进入catch
我的程序是用tcpclient与几十台下位机通讯。在论坛大神的帮助下,程序写成了这个样子。
private void frmMain_Load(object sender, EventArgs e)
{
proc();
}
private void proc()
{
timer = new System.Threading.Timer(h =>
{
if (enableComm)
{
foreach (var s in Session.Stations)
{
var station = Session.Stations.Find(p => p.Id == s.Id);
if (station.IsWorking == true)
{
if (!comm.COMMStates.ContainsKey(station.Id))
{
comm.COMMStates[station.Id] = new COMMState()
{
Station = station,
Data = new byte[250],
StationErrNum = 0,
Exception = null,
TcpClient = null
};
}
ThreadPool.QueueUserWorkItem(x => ThreadPollCallback(comm.COMMStates[station.Id]));
}
}
}
},null,0,1000);
}
public void ThreadPollCallback(object state)
{
var cs = state as COMMState;
if (cs == null) return;
var station = cs.Station;
//防止在connect 过程中再次连接,因为下位机只允许3个连接
if (cs.COMMUNICATION_STATE == COMMUNICATIONSTATE.连接&&cs.TriesNum>=3)
{
lock (lockObj)
{
cs.Exception = new Exception("communication timeout");
}
return;
}
cs.Thread = Thread.CurrentThread;
try
{
//连接
if (cs.TcpClient == null || !cs.TcpClient.Connected)
{
lock (lockObj)
{
cs.COMMUNICATION_STATE = COMMUNICATIONSTATE.连接;
cs.TriesNum++;
}
cs.TcpClient = new TcpClient(cs.Station.IP, 502);
}
TcpClient tc = cs.TcpClient;
lock (lockObj)
{
cs.COMMUNICATION_STATE = COMMUNICATIONSTATE.开始;
}
//读数据,实际就是write之后read
ModbusIpMaster master = ModbusIpMaster.CreateIp(tc);
ushort startAddress = 0;
ushort numInputs = 125;
ushort[] res = master.ReadHoldingRegisters(startAddress, numInputs);
lock (lockObj)
{
//处理数据,保存到数据库
cs.COMMUNICATION_STATE = COMMUNICATIONSTATE.完成;
}
}
catch (Exception e)
{
cs.COMMUNICATION_STATE = COMMUNICATIONSTATE.故障;
}
finally
{
}
}
现在的问题是,程序运行一个多小时后,通讯就会中断,断点发现这时候程序根本就不执行ThreadPollCallback,而且整个程序变得非常慢,感觉就像是线程池已经用完了,再有新的线程也不理会一样。
我猜想可能与tcp连接失败有关。
因为下位机中经常有一些没有连到网络,所以有一些线程是在不断重复“connect,失败”的过程。看上去这个过程每秒都要新开一个线程来做,而且旧的线程并不会被回收。
求助,这个问题怎么办啊?
------解决思路----------------------
就你这一句话,就知道你的线程池为啥满了……
你为啥要开新线程去判断是否能通讯呢?为什么不能再fail后再此线程内继续连接呢?
------解决思路----------------------
防止重入也有问题,因为操作实际上是write之后等回复,现在就是write完之后read,如果下位机不回复就会一直等着。这时候只好重入一下,再write一次试试。
设置超时时间啊,超时了还没有回复,就别等了
我多次用收快递来打比方.
你从网上订购东西,就相当于是发送请求
你要接收数据,就好比是等快递.
等快递有很多种办法,
1.异步的方式就是快递来了放门卫,门卫给你打电话,然后你去取.
当然快递一直不来,门卫就一直不给你打电话,你需要自己设置个定时器,判断时间太长了怎么还没到,然后自己打电话去催.
2.同步的方式就是你订货之后,就没事去门卫那里溜达溜达,看看货到是没到.
而你现在就是用同步的思想来做.
同步的思想再加上线程池的概念,就是你自己不去看,而是派个人去看.
而你没告诉派去的人要等多长时间还不来就回来,而是没来就一直在那里等.
然后你又在时间过长之后,又派新的人去看.
导致门卫那里堵了一大堆人都在帮你等快递,这有任何意义??
------解决思路----------------------
设置ReceiveTimeout之后,如果超时了还没有数据到达,就会报个错误,进入catch