C# Monitor 使用失败

nihao595 2014-08-26 03:30:08
C#中 使用收发线程进行串口通讯。使用独立线程类对串口进行同步读写操作。
接收线程 收到有效数据后,调用 MainWindow中RemoveCurCmd方法移除发送队列中第一条指令。
发送线程自发送队列获取一条指令进行发送。
各个按钮或定时器 调用 MainWindow中AddCmd方法向发送队列中加入一条指令。

现在发现 互斥锁无效,如下代码,执行 RemoveCurCmd()时,发送队列的内容仍然发送变化,即 AddCmd()仍然在向队列添加内容,请大家帮忙分析原因,谢谢。

public static void RemoveCurCmd()
{
try
{
Monitor.TryEnter(monitorCmdSendBuf);
Debug.WriteLine("GetCmdSendNum():{0}", GetCmdSendNum());
if (GetCmdSendNum() > 1)
{
//移走发送完的命令
for (int k = 0; k < GetCmdSendNum() - 1; k++)
m_cmdSendBuf[k] = m_cmdSendBuf[k + 1];

}
else if (GetCmdSendNum() == 1)
{
CMD byCmd = new CMD();
m_cmdSendBuf[0] = byCmd;
}

//数据长度减 一
SetCmdSendNum(GetCmdSendNum() - 1);
Debug.WriteLine("GetCmdSendNum():{0}", GetCmdSendNum());
Monitor.PulseAll(monitorCmdSendBuf);
}
finally
{
Monitor.Exit(monitorCmdSendBuf);
}
}

public static bool AddCmd(CMD byCmd, //要插入的命令
int uiCmdNumber, //要插入的命令条数
int nPostion //要插入命令队列的位置
)
{
try
{
Monitor.TryEnter(monitorCmdSendBuf);

//临时缓冲区
CMD[] cmdSendBuf = new CMD[MAX_CMD_NUM];

//每次新添加指令 放置到最先发送位置,导致某些指令一直不能被发送-----所以放置到队列的最后一个
if (GetCmdSendNum() < MAX_CMD_NUM)
{
//nPostion 为当前 发送队列数量
m_cmdSendBuf[nPostion] = byCmd;
string strPrint = string.Format("nPostion:{0}", nPostion);
Debug.Print(strPrint);
}
}
else if (GetCmdSendNum() > 0)
{
//nPostion 为当前 发送队列数量
m_cmdSendBuf[nPostion] = byCmd;
string strPrint = string.Format("nPostion:{0}", nPostion);
Debug.Print(strPrint);
}
else
{
//当前发送队列为空
//将指令放置到发送队列

for (int i = 0; i < CMDSENDBUFSIZE - 1; i++)
{
m_cmdSendBuf[m_byCmdSendNum].data[i] = byCmd.data[i];
}
m_cmdSendBuf[m_byCmdSendNum].len = byCmd.len;
m_cmdSendBuf[m_byCmdSendNum].delay = byCmd.delay;
}

m_byCmdSendNum += uiCmdNumber;

Monitor.PulseAll(monitorCmdSendBuf);
}
finally
{
Monitor.Exit(monitorCmdSendBuf);
}
return true;
}
...全文
391 16 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
於黾 2014-08-27
  • 打赏
  • 举报
回复
AddCmd是个啥,根本没有发有关代码,谁知道你哪里逻辑错误了
nihao595 2014-08-27
  • 打赏
  • 举报
回复
小弟发现还有一个问题: 1. 定义命令类 如下: /// <summary> /// 命令 类: /// </summary> public class CMD { public short len; //命令长度 public byte[] data; //命令数据 public short delay; //命令延时 public bool obstruct;//是否阻塞发送 public CMD() { len = 0;//当前该条指令长度为 0 data = new byte[MainWindow.CMDSENDBUFSIZE]; delay = 10;//ms 默认 obstruct = false;/*false;//不阻塞发送*/ /*true;//阻塞发送*/ } }; 2. 定义静态成员 如下: //发送缓冲区 private static CMD[] m_cmdSendBuf = new CMD[MAX_CMD_NUM]; 3. 将指令添加到 待发送队列: //读取:添加指令到发送队列 MainWindow.AddCmd(cmdSend, nSendNum, MainWindow.GetCmdSendNum()); 发现:刚刚调用进入 AddCmd( ),还没有进入队列,队列的第一条内容已经是即将被添加的内容,即 刚刚想添加的内容会覆盖 发送队列中第一条内容。实际是 该条会覆盖发送队列中所以内容,其它地方没有对发送队列处理,所以非常疑惑。
puler 2014-08-27
  • 打赏
  • 举报
回复
有点意思,看看再说
showjim 2014-08-27
  • 打赏
  • 举报
回复
- Try
於黾 2014-08-27
  • 打赏
  • 举报
回复
另外,monitorCmdSendBuf是什么东东,定义在哪 能够断定锁定的是同一对象么?
nihao595 2014-08-27
  • 打赏
  • 举报
回复
最终发现问题在这里,但是不知道为什么,请大家指教: CMD cmdSend = new CMD(); MainWindow.CreateCmd(MainWindow.CMD_GAD_TOTALFLOOR, null, 0, ref cmdSend.data, ref cmdSend); nSendNum++; //读取:添加指令到发送队列 MainWindow.AddCmd(cmdSend, nSendNum, MainWindow.GetCmdSendNum()); //添加到被发送队列后将 待添加数量置为 0. nSendNum = 0; 每条指令组建后,保存为 cmdSend 对象,该对象内容被 AddCmd() 添加到发送队列。实际 CreateCmd()执行后 发送队列内容就被更改了,这点不懂啊。
於黾 2014-08-27
  • 打赏
  • 举报
回复
刚刚调用进入 AddCmd( ),还没有进入队列,队列的第一条内容已经是即将被添加的内容 断点,一步一步跟,从主窗口的构造函数开始跟,看到底哪一步修改的. 或者右键,查找所有引用,看到底都有哪些地方会修改
nihao595 2014-08-27
  • 打赏
  • 举报
回复
在不启动线程的情况下回出现此问题,启动线程时情况更复杂,不过也类似。
ysd_xwl 2014-08-27
  • 打赏
  • 举报
回复
线程执行顺序的问题
於黾 2014-08-27
  • 打赏
  • 举报
回复
你调试的时候已经把开线程的地方都给注释掉了?
nihao595 2014-08-27
  • 打赏
  • 举报
回复
现在非常困惑到底是什么地方改变了发送队列的内容。
nihao595 2014-08-27
  • 打赏
  • 举报
回复
AddCmd() 方法在最上边。
nihao595 2014-08-26
  • 打赏
  • 举报
回复
也就是说 需要处理无法锁定资源的情况,等待,直到可以锁定资源为止?
wangxingge2010 2014-08-26
  • 打赏
  • 举报
回复
同楼上, TryEnter. 。还有一句话要说的就是MS那些老头子们设计出来的API是有用的,只不过是你还不会用,遇事多想想
Forty2 2014-08-26
  • 打赏
  • 举报
回复
bool Monitor.TryEnter(...) 你不判断下锁是否成功?
bdmh 2014-08-26
  • 打赏
  • 举报
回复
你是怎么判断在添加内容,RemoveCurCmd中每次exit后,就有可能执行add操作,你是在exit前检测发生变化了,如何检测的

111,098

社区成员

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

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

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