for (int i = 0; i < axiss.Length; i++)
{
int axis = axiss[i];
LogHelper.Write($"1--执行的轴号是{axis}");
var dyminW = new DummyWork2();
dyminW.ZMotionDammyReady += new DummyWork2.ZAxisDyminWorkingEndEvent(OnDyminWorkingEnd);
dyminW.zAxisDyminDropSenderEnd += new DummyWork2.ZAxisDyminDropSenderEndEvent(DropSender);
dyminW.Start(axis, 0);
LogHelper.Write($"2--执行的轴号是{axis}");
dummyWork2s.Add(dyminW);
}
通过上面的方式去调用下面的代码,下面的代码里面会经常使用Task.Run()异步线程进行硬件操作,最多一次控制6个轴(也就是new 6个DummyWork2),轴操作分为回吸运动和滴下运动,没管大概10000000的量,每次滴下大概1-20000,现在需要6个轴一起连续滴多少次(客户设置一般800-2000次)。现在遇到一个问题,就是我运动过程中会有某个轴突然停止运动,似乎是线程假死,有时候哪个轴就直接停止运动,有时候突然过段时间又开始运动,有的时候开启下次任务时,突然又接着上次的任务次数接着运动。哪位大佬帮忙看看,怎么解决?
public class DummyWork2
{
public delegate void ZAxisDyminWorkingEndEvent(int axis, bool success);
/// <summary>
/// 轴工作已完成触发
/// </summary>
public ZAxisDyminWorkingEndEvent ZMotionDammyReady;
public delegate void ZAxisDyminDropSenderEndEvent(int axis, int dropNum, int num);
public ZAxisDyminDropSenderEndEvent zAxisDyminDropSenderEnd;
public int Suckvalue;
public int SuckSpeed;
public int DropSpeed;
public int DropPulse;
public int DropNumber;
public int DyminNum;
public int DummyStartNum;
public int Axis = -1;
public int Num = 1;
public int IntervalTime = Commond.Commond.ReadJson.typeNumber.IntervalTime;
///获取每个轴的回吸量
public int SuckUnm()
{
try
{
LogHelper.Write($"{Axis}轴SuckUnm start!");
int position = 0;
var ans = Commond.Commond.Mc210Contorl.SscGetPosition(1, 1, Axis + 1, out position);
if (ans != "success")
{
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_OPERATION);
Thread.Sleep(50);
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_SYSTEM);
Thread.Sleep(50);
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_SERVO);
Thread.Sleep(50);
SuckUnm();
}
var number = Convert.ToInt32(Commond.Commond.ReadJson.auto[Axis].SuckValue) - Convert.ToInt32(position);
LogHelper.Write($"{Axis}轴SuckUnm end!");
return number;
}
catch (Exception ex) { return 0; }
}
System.Threading.Timer _SuckState;
///回吸动作
public void Suck(int dummyStartNum)
{
try
{
CancellationTokenSource cts = new CancellationTokenSource();
Task.Run(() =>
{
try
{
LogHelper.Write($"{Axis}轴回吸开始!");
DummyStartNum = dummyStartNum;
Suckvalue = SuckUnm();
LogHelper.Write($"{Axis}轴回吸量:{Suckvalue}!");
ZMotionTools.SetOp(Commond.Commond.IOConfig.ValveReverse[Axis], 0);
ZMotionTools.SetOp(Commond.Commond.IOConfig.ValveCorotation[Axis], 1);
if (Commond.Commond.Mc210WorkingStop)
{
LogHelper.Write($"{Axis}轴停止任务!");
_SuckState.Dispose();
cts.Cancel();
cts.Dispose();
AxisState = 1;
return;
}
var ret = Commond.Commond.Mc210Contorl.SscIncStart(1, 1, Axis + 1, Suckvalue, SuckSpeed, 1, 3);
if (ret != "success")
{
LogHelper.Write($"{Axis}轴回吸失败!");
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_OPERATION);
Thread.Sleep(50);
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_SYSTEM);
Thread.Sleep(50);
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_SERVO);
Thread.Sleep(50);
if (Commond.Commond.Mc210WorkingStop)
{
LogHelper.Write($"{Axis}轴停止任务!");
_SuckState.Dispose();
cts.Cancel();
cts.Dispose();
AxisState = 1;
return;
}
ret = Commond.Commond.Mc210Contorl.SscIncStart(1, 1, Axis + 1, Suckvalue, SuckSpeed, 1, 3);
if (ret != "success")
{
cts.Cancel();
cts.Dispose();
AxisState = 1;
WarnTools.Warn($"{Axis + 1}轴回吸失败", WarnTypeENum.P轴报警, true, 1);
LogHelper.Write($"{Axis + 1}轴回吸失败");
return;
}
}
int Timeout = Convert.ToInt32(Suckvalue / (SuckSpeed));
int count = 0;
int state;
_SuckState = new Timer((s) =>
{
if (Commond.Commond.Mc210WorkingStop)
{
LogHelper.Write($"{Axis}轴停止任务!");
_SuckState.Dispose();
cts.Cancel();
cts.Dispose();
AxisState = 1;
return;
}
var status = Commond.Commond.Mc210Contorl.SscGetDriveFinStatus(1, 1, Axis + 1, SscApi.SSC_FIN_TYPE_SMZ, out state);
if (status == "success")
{
if (state == 1)
{
_SuckState.Dispose();
LogHelper.Write($"{Axis}轴回吸完成,开始第{dummyStartNum}任务!");
cts.Cancel();
cts.Dispose();
Dummy();
}
}
else
{
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_OPERATION);
Thread.Sleep(50);
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_SYSTEM);
Thread.Sleep(50);
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_SERVO);
Thread.Sleep(50);
}
if (count > 20)
{
_SuckState.Dispose();
cts.Cancel();
cts.Dispose();
AxisState = 1;
WarnTools.Warn($"{Axis + 1}轴吐料模式回吸超时!", WarnTypeENum.P轴报警, true, 1);
LogHelper.Write($"{Axis + 1}轴吐料模式回吸超时");
return;
}
count++;
}, null, Timeout, 500);
}
catch (Exception ex)
{
cts.Cancel();
cts.Dispose();
AxisState = 1;
WarnTools.Warn($"{Axis + 1}轴吐料模式回吸错误:{ex.Message}!", WarnTypeENum.P轴报警, true, 1);
LogHelper.Write($"{Axis + 1}轴吐料模式回吸错误:{ex.Message}");
}
}, cts.Token);
}
catch (Exception ex)
{
LogHelper.Write($"{Axis + 1}轴吐料模式回吸错误:{ex.Message}");
AxisState = 1;
}
}
///滴下动作,当剩余的量不够滴下动作时回吸
public void Dummy()
{
CancellationTokenSource cts = new CancellationTokenSource();
LogHelper.Write($"Dummy Start1->{Axis} DummyStartNum {DummyStartNum} DyminNum {DyminNum}");
var dummy = Task.Run(() =>
{
try
{
LogHelper.Write($"Dummy Start2->{Axis}");
for (int i = DummyStartNum; i < DyminNum; i++)
{
ZMotionTools.SetOp(Commond.Commond.IOConfig.ValveReverse[Axis], 0);
ZMotionTools.SetOp(Commond.Commond.IOConfig.ValveCorotation[Axis], 0);
DropSenser.Zero(DropSenserNum(Axis));
for (int j = 0; j < DropNumber; j++)
{
if (Commond.Commond.Mc210WorkingStop)
{
cts.Cancel();
cts.Dispose();
AxisState = 1;
LogHelper.Write($"Dummy stop->{Axis}");
return;
}
var ret = Commond.Commond.Mc210Contorl.SscIncStart(1, 1, Axis + 1, -DropPulse, DropSpeed, 1, 5);
if (ret == "success")
{
Thread.Sleep(Convert.ToInt32(Commond.Commond.ReadJson.auto[Axis].DropInterval) + Convert.ToInt32(DropPulse / (DropSpeed)));
}
else
{
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_OPERATION);
Thread.Sleep(10);
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_SYSTEM);
Thread.Sleep(10);
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_SERVO);
Thread.Sleep(10);
Commond.Commond.Mc210Contorl.SscIncStart(1, 1, Axis + 1, -DropPulse, DropSpeed, 1, 5);
}
}
zAxisDyminDropSenderEnd?.Invoke(Axis, DropSenser.GetCount(DropSenserNum(Axis)), i + 1);
int position = 0;
var ans = Commond.Commond.Mc210Contorl.SscGetPosition(1, 1, Axis + 1, out position);
if (ans != "success")
{
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_OPERATION);
Thread.Sleep(50);
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_SYSTEM);
Thread.Sleep(50);
Commond.Commond.Mc210Contorl.SscResetAlarm(1, 1, Axis + 1, SscApi.SSC_ALARM_SERVO);
Thread.Sleep(50);
Commond.Commond.Mc210Contorl.SscGetPosition(1, 1, Axis + 1, out position);
}
if (position > DropPulse * DropNumber)
{
Thread.Sleep(IntervalTime);
}
else
{
cts.Cancel();
cts.Dispose();
Suck(i + 1);
return;
}
}
AxisState = 1;
return;
}
catch (Exception ex)
{
cts.Cancel();
cts.Dispose();
WarnTools.Warn($"{Axis}轴Dummy运动错误:{ex.Message}", WarnTypeENum.P轴报警, true, 1);
LogHelper.Write($"{Axis}轴Dummy运动错误:{ex.Message}");
AxisState = 1;
}
}, cts.Token);
}
public int DropSenserNum(int input)
{
try
{
int num = 0;
switch (input)
{
case 0:
num = Commond.Commond.IOConfig.InputAxis0DorpSenser;
break;
case 1:
num = Commond.Commond.IOConfig.InputAxis1DorpSenser;
break;
case 2:
num = Commond.Commond.IOConfig.InputAxis2DorpSenser;
break;
case 3:
num = Commond.Commond.IOConfig.InputAxis3DorpSenser;
break;
case 4:
num = Commond.Commond.IOConfig.InputAxis4DorpSenser;
break;
case 5:
num = Commond.Commond.IOConfig.InputAxis5DorpSenser;
break;
default:
num = 0;
break;
}
return num;
}
catch (Exception ex)
{
return -1;
}
}
public void Start(int axis, int type)
{
CancellationTokenSource cts = new CancellationTokenSource();
var a = Task.Run(() =>
{
try
{
//工作流程
//状态监听
Axis = axis;
SuckSpeed = Commond.Commond.UCMppConditions.MPPSuckSpeed[axis];
DropSpeed = Commond.Commond.UCMppConditions.MPPDropSpeed[axis];
DropPulse = Convert.ToInt32(Commond.Commond.ReadJson.auto[axis].StandardPulse);
DropNumber = Convert.ToInt16(Commond.Commond.ReadJson.auto[axis].DropCount);
if (type == 0)
Num = Commond.Commond.ReadJson.typeNumber.DyminNum;
else
Num = Commond.Commond.ReadJson.typeNumber.Dymin2Num;
Suckvalue = Convert.ToInt32(Commond.Commond.ReadJson.auto[Axis].SuckValue);
DyminNum = Convert.ToInt32(Suckvalue / (DropPulse * DropNumber)) * Num;
LogHelper.Write($"Start的轴号是{Axis}");
if (Commond.Commond.Mc210WorkingStop)
{
LogHelper.Write($"{Axis}轴停止任务!");
_SuckState.Dispose();
cts.Cancel();
cts.Dispose();
AxisState = 1;
return;
}
cts.Cancel();
cts.Dispose();
Suck(0);
}
catch (Exception ex)
{
cts.Cancel();
cts.Dispose();
WarnTools.Warn($"{axis + 1}轴运动报错:{ex.Message}", WarnTypeENum.P轴报警, true, 1);
AxisState = 1;
}
}, cts.Token);
}
public int axisState;
public int AxisState
{
get => axisState;
set
{
axisState = value;
if (axisState == 1)
{
LogHelper.Write($"{Axis}轴完成");
ZMotionDammyReady?.Invoke(Axis, true);
}
}
}
}
C#多线程假死或卡死问题
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
40条回答 默认 最新
M_try的小尾巴 2024-11-27 10:54关注获得0.15元问题酬金 提示: 本回答参考 AIGC,由本人审核整理提供。若问题解决,望采纳;如仍有疑问,请评论回复。
问题分析
从代码和描述来看,问题主要集中在多线程操作中,特别是使用
Task.Run()进行硬件操作时,某些轴可能会突然停止运动,表现为线程假死或卡死。这种情况可能是由于以下几个原因导致的:- 资源竞争:多个线程同时访问和修改共享资源,导致资源竞争和死锁。
- 硬件操作阻塞:硬件操作可能因为某些原因(如硬件故障、通信问题等)导致线程阻塞。
- 任务取消和异常处理:任务取消和异常处理不当可能导致线程无法正常结束。
- 线程同步问题:线程间的同步机制可能存在问题,导致某些线程无法正常执行。
解决方案
1. 资源竞争问题
确保所有共享资源(如硬件控制接口、状态变量等)在多线程环境下是线程安全的。可以使用
lock关键字或其他同步机制来保护共享资源。private readonly object _lock = new object(); public void Suck(int dummyStartNum) { lock (_lock) { // 保护共享资源的操作 } }2. 硬件操作阻塞问题
在硬件操作中加入超时机制,避免因硬件问题导致线程长时间阻塞。可以使用
Task.WaitAsync或CancellationToken来实现超时控制。public async Task SuckAsync(int dummyStartNum, CancellationToken cancellationToken) { try { var result = await Commond.Commond.Mc210Contorl.SscIncStartAsync(1, 1, Axis + 1, Suckvalue, SuckSpeed, 1, 3, cancellationToken); if (result != "success") { // 处理错误 } } catch (OperationCanceledException) { // 处理超时 } }3. 任务取消和异常处理
确保在任务取消时,所有资源都被正确释放,并且异常被正确捕获和处理。
public void Suck(int dummyStartNum) { using (var cts = new CancellationTokenSource()) { try { Task.Run(() => { try { // 任务逻辑 } catch (Exception ex) { // 异常处理 } }, cts.Token); } catch (Exception ex) { // 异常处理 } } }4. 线程同步问题
确保线程间的同步机制是正确的。可以使用
SemaphoreSlim或ManualResetEvent等同步原语来控制线程的执行顺序。private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); public async Task SuckAsync(int dummyStartNum) { await _semaphore.WaitAsync(); try { // 任务逻辑 } finally { _semaphore.Release(); } }总结
通过以上方法,可以有效减少多线程操作中的假死或卡死问题。具体实施时,需要根据实际情况选择合适的同步机制和异常处理策略。同时,建议在开发过程中加入详细的日志记录,以便在问题发生时能够快速定位和解决问题。
评论 打赏 举报解决 1无用