首页 新闻 会员 周边 捐助

C# 使用Action时抛出异常

0
悬赏园豆:100 [已解决问题] 解决于 2019-05-22 10:42

我在写一个事件调度器的回调方法时,碰到了一个奇怪的问题:

private void TimeCallBackFunction()
{
      Action task;
      while ((task = PopWithPushNext(DateTime.Now)) != null)
      {
          ThreadPool.QueueUserWorkItem(useless => task.Invoke(), null); // throw an System.NullReferenceException, task是null
      }
      Thread.Sleep(1000);
}

我觉得奇怪的是明明在上面已经判断过task是否为null了,但是还是会报这个异常(异常并不总是出现),task是一个局部变量,外围没有申明过同名的静态变量;这个是个单线程方法。
希望有遇到过这类问题或者清除原因的大佬可以帮我解答一下这个疑惑。

问题补充:

修改之后的代码

private void TimeCallBackFunction()
{
    Action action;
    while ((action = PopWithPushNext(DateTime.Now)) != null)
    {
        Action task = new Action(action);//重新创建一个action的拷贝
        ThreadPool.QueueUserWorkItem(useless => task());
    }
    Thread.Sleep(1000);
}

这样就可以解决这个问题了。

一棵猪油草的主页 一棵猪油草 | 初学一级 | 园豆:114
提问于:2019-05-22 09:02

你怎么确定task是null的?

dudu 5年前

@dudu: 因为编译器抛出的异常说task是null,抛出异常后我查询了task的值,确实也是为null。

一棵猪油草 5年前

@一棵猪油草: 修改后的代码还有一个地方不同,没有使用 Invoke

dudu 5年前
< >
分享
最佳答案
0

试试把 Action 改为 Task ,Task task;

收获园豆:50
dudu | 高人七级 |园豆:30585 | 2019-05-22 10:07

我觉得有没有可能对于ThreadPool来说我的task变量不是线程安全的,后续当task的值被修改为null的时候,加入到线程池的时候报了这个问题。因为我while循环的时候task是会变为null。

一棵猪油草 | 园豆:114 (初学一级) | 2019-05-22 10:26

@一棵猪油草: 建议提供重现这个问题的示例代码

dudu | 园豆:30585 (高人七级) | 2019-05-22 10:38

@一棵猪油草: 你这个只是解决了 Access to modified closure 问题,直接通过 var action1 = action 就行,这两者是不同的行为。

BUTTERAPPLE | 园豆:3190 (老鸟四级) | 2019-05-22 11:00
其他回答(3)
0

是task==null,还是 task的方法里面有null exception

收获园豆:10
czd890 | 园豆:14488 (专家六级) | 2019-05-22 09:32

System.NullReferenceException:“未将对象引用设置到对象的实例。”

task 是 null。

支持(0) 反对(0) 一棵猪油草 | 园豆:114 (初学一级) | 2019-05-22 10:02
0
class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            TimeCallbackFunc();
        }

        static void TimeCallbackFunc()
        {
            Action task;
            while ((task = PopWithPushNext(DateTime.Now)) != null)
            {
                ThreadPool.QueueUserWorkItem(useless => task.Invoke(), null);
            }
        }

        static Action PopWithPushNext(object value)
        {
            return () => { Console.WriteLine("Current Time is ={0}", value); };
        }
    }

我简单写了一个Sample,是没有问题的。建议提供一下你的 回调函数 PopWithPushNext

收获园豆:40
BUTTERAPPLE | 园豆:3190 (老鸟四级) | 2019-05-22 10:17

QueueUserWork 接收的委托定义为
public delegate void WaitCallback(object state);

支持(0) 反对(0) BUTTERAPPLE | 园豆:3190 (老鸟四级) | 2019-05-22 10:25
ThreadPool.QueueUserWorkItem(state => Console.WriteLine("Hello,This is my function= {0}", state), DateTime.Now);

拆分开模拟一下,看哪里出问题。

支持(0) 反对(0) BUTTERAPPLE | 园豆:3190 (老鸟四级) | 2019-05-22 10:28

@BUTTERAPPLE: 感谢回复,我已经找到问题了,原因是相对于ThreadPool来说task变量并不是一个线程安全的值,它可能变为null的时候再添加到线程池的时候抛出了这个异常。感谢。

支持(0) 反对(0) 一棵猪油草 | 园豆:114 (初学一级) | 2019-05-22 10:40
0

Action task当然是null了,你这句代码只是定义了一个task并没有实例化。

又见阿郎 | 园豆:163 (初学一级) | 2019-05-27 12:36
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册