微信公众平台官方网站,大良网站建设价位,潍坊市企业网站建设,新能源电动汽车问题代码#xff1a;
//以下为现有代码的大概描述#xff0c;只可意会#xff0c;不可执行#xff01;#xff01;#xff01;QueueMove mQueue new QueueMove();
//该接口为下面描述线程A、线程B调用的接口
private void ActionTrigger(Move move)//M…问题代码
//以下为现有代码的大概描述只可意会不可执行QueueMove mQueue new QueueMove();
//该接口为下面描述线程A、线程B调用的接口
private void ActionTrigger(Move move)//Move表示一个类由外部传入
{lock(mlock){ this.DoMove1(move);//将move压入队列ThreadPool.QueueUserWorkItem(new WaitCallback(this.DoMove2());//启用多线程将move弹出并执行相关动作。}
}private void DoMove1(Move move)
{lock(mlockEn){mQueue.Enqueue(move);}
}private void DoMove2(object obj)
{lock(mlockDe){while(mQueue.Count0){Move mtmp mQueue.Dequeue();//通过打印mtmp地址、mtmp中变量指向的地址发现出现问题时连续添加的Move均被最后一个元素覆盖。//根据mtmp执行相关耗时动作}}
}
问题背景
1.一个线程A不间断向Queue压入元素压入元素后会启动多线程进行元素弹出执行相关耗时动作。
2.启动另外一个线程B连续向Queue压入元素。
问题现象
线程B连续压入的元素弹出的元素值均为最后一次压入的元素值。
问题原因
网上查找问题原因
1C#中的Queue类是一个先进先出FIFO的数据结构它使用一个数组来存储队列中的元素。当你向一个空的Queue中添加元素时它会直接存储在数组的第一个位置上。
当你弹出一个元素后Queue会将数组中的元素向前移动一个位置填补被弹出的元素位置。这样新添加的元素会被放置在队列的末尾。
所以如果你在没有弹出队列中的所有元素之前再次添加一个元素那么这个新添加的元素会被放置在队列的末尾。当你继续弹出元素时它们将按照添加的顺序依次被弹出而最后一个添加的元素将成为队列中的第一个元素并且覆盖之前添加的元素。
如果你希望保留之前添加的元素并且不被覆盖你可以在添加新元素之前先将队列中的所有元素弹出然后再将它们添加回队列中。或者你可以考虑使用其他数据结构比如List根据需要进行操作。
2网上查找给出一定思路本身Queue不是线程安全的那么采用线程安全的队列ConcurrentQueue()但问题依然存在。
3继续以ConcurrentQueue进行排查
C#的ConcurrentQueue是一种线程安全的队列可以在多线程环境下进行并发操作。当一个线程在另一个线程执行弹出操作期间连续添加元素时导致新添加的元素覆盖之前已经弹出的值的原因可能是由于在弹出操作期间另一个线程执行了入队操作导致队列被修改。
由于ConcurrentQueue是线程安全的它内部使用了一些同步机制来确保多个线程可以安全地对队列进行操作。但是即使使用了同步机制当一个线程在另一个线程执行弹出操作期间连续添加元素时也可能会发生竞争条件。这种竞争条件会导致新添加的元素覆盖之前已经弹出的值。
为了解决这个问题你可以在添加元素之前先判断队列是否为空或者使用锁来保护对队列的并发操作。另外你还可以考虑使用其他数据结构或者调整程序逻辑来避免这种情况的发生。
问题确认
1在压入队列前、弹出队列后均进行变量指向地址的打印发现地址相同可以明确数据被覆盖。 问题解决
1采用Lock锁确保线程B同次的压入和弹出在一次执行完成。即重写ActionTrigger()方法用于线程B的调用并且删除ThreadPool多线程处理。