当前位置: 首页 > 编程语言 > C#

创建线程共享时出现NullReferenceException

时间:2023-04-10 11:21:43 C#

创建线程时出现NullReferenceException我正在看这个线程来创建一个简单的线程池。在那里,我遇到了@MilanGardian对.NET3.5的回应,它非常优秀并符合我的目标:usingSystem;使用System.Collections.Generic;使用系统线程;namespaceSimpleThreadPool{publicsealedclassPool:IDisposable{publicPool(intsize){this._workers=newLinkedList();对于(vari=0;i0){Monitor.Wait(this._tasks);}this._disposed=true;Monitor.PulseAll(this._tasks);//唤醒所有工作人员(此时他们都不会处于活动状态;处置标志将导致then完成,以便我们可以加入他们)waitForThreads=true;}}if(waitForThreads){foreach(varworkerinthis._workers){worker.Join();}}}publicvoidQueueTask(Actiontask){lock(this._tasks){if(this._disallowAdd){thrownewInvalidOperationException("ThisPoolinstanceisintheprocessofbeingbeingdisposed,can'taddanymore");}if(this._disposed){thrownewObjectDisposedException("ThisPoolinstancehasalreadybeendisposed");}this._tasks.AddLast(任务);Monitor.PulseAll(this._tasks);//脉冲因为任务计数改变了}}privatevoidWorker(){Actiontask=null;while(true)//循环直到线程池被释放{lock(this._tasks)//找到一个任务需要是原子的{while(true)//等待我们进入_workers队列和一个可用的任务{if(this._disposed){返回;}if(null!=this._workers.First&&object.ReferenceEquals(Thread.CurrentThread,this._workers.First.Value)&&this._tasks.Count>0)//只有轮到我们时我们才能领取任务(此工作线程是_worker队列中的第一个条目)并且有一个任务可用{task=this._tasks.First.Value;这个._tasks.RemoveFirst();这个._workers.RemoveFirst();Monitor.PulseAll(this._tasks);//脉冲,因为当前(第一个)worker改变了(这样下一个可用的休眠worker将接手它的任务)break;//我们找到了一个要处理的任务,从上面的'while(true)'循环中跳出}Monitor.Wait(this._tasks);//去睡觉,要么不our轮到或没有任务处理}}task();//处理找到的任务this._workers.AddLast(Thread.CurrentThread);任务=空;}}私人只读LinkedList_workers;//准备好处理操作的工作线程队列privatereadonlyLinkedList_tasks=newLinkedList();//要由工作线程处理的操作privatebool_disallowAdd;//处理队列时设置为真,但仍有任务待处理privatebool_disposed;//当处理队列并且没有更多任务挂起时设置为true}publicstaticclassProgram{staticvoidMain(){using(varpool=newPool(5)){varrandom=newRandom();Actionrandomizer=(index=>{Console.WriteLine("{0}:Workingonindex{1}",Thread.CurrentThread.Name,index);Thread.Sleep(random.Next(20,400));控制台。WriteLine("{0}:结束{1}",Thread.CurrentThread.Name,index);});对于(vari=0;i随机化器(i1));}}}}}我使用如下:staticvoidMain(string[]args){......while(keepRunning){...池。QueueTask(()=>DoTask(eventObject);}...}privatestaticvoidDoTask(EventObjecte){//做一些计算pool.QueueTask(()=>DoAnotherTask(eventObject));//这是一个相对较小的计算}运行代码大约两天后,我得到以下异常:未处理的异常:System.NullReferenceException:对象引用未设置为对象的实例。在System.Collections.Generic.LinkedList`1.InternalInsertNodeBefore(LinkedListNode`1个节点,LinkedListNode`1newNode)在System.Collections.Generic.LinkedList`1.AddLast(Tvalue)在MyProg.Pool.Worker()在System.Threading.ThreadHelper.ThreadStart_Context(Objectstate)在System.Threading。ExecutionContext.Run(ExecutionContextexecutionContext,ContextCallbackcallback,Objectstate)atSystem.Threading.ThreadHelper.ThreadStart()我不知道是什么原因造成的,因为我无法再次收到关于如何解决这个错误的错误这个问题,有什么建议吗?似乎对_workers链表的访问没有正确同步。考虑这种情况:让我们假设在某个时候this._workets列表包含一个项目。第一个线程调用this._workers.AddLast(Thread.CurrentThread);但在一个非常具体的地方被打断了——在AddLast()方法中:publicvoidAddLast(LinkedListNodenode){this.ValidateNewNode(node);if(this.head==null){this.InternalInsertNodeToEmptyList(node);}else{//在这里我们被打断了——列表不为空,//但很快就会发生,并且this.head变为null//InternalInsertNodeBefore()不期望this.InternalInsertNodeBefore(this.head,node);}node.list=(LinkedList)这个;其他线程调用this._workers.RemoveFirst();。该语句周围没有lock(),因此它完成并且列表现在为空。AddLast()现在应该调用InternalInsertNodeToEmptyList(node);但它不能,因为条件已经被评估过。在单个this._workers.AddLast()行周围放置一个简单的lock(this._tasks)可以防止这种情况发生。其他不好的情况包括两个线程同时向同一个列表添加项目。我想我发现了问题。代码示例缺少lock()privatevoidWorker(){Actiontask=null;while(true)//循环直到线程池被释放{lock(this._tasks)//找到一个任务需要是原子的{while(true)//等待我们进入_workers队列和一个可用的任务{....}}任务();//处理找到的任务this._workers.AddLast(Thread.CurrentThread);任务=空;}}锁应该扩展或包装在this._workers.AddLast(Thread.CurrentThread);如果您查看其他修改LinkedList(Pool.QueueTask)的代码,它将被包裹在一个锁中。以上就是C#学习教程的全部内容:创建线程时出现NullReferenceException。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右边联系管理员删除。如需转载请注明出处:

最新推荐
猜你喜欢