首页 新闻 会员 周边

Task.Run直接读取外部参数,会造成线程不安全?

1
悬赏园豆:30 [已解决问题] 解决于 2014-08-21 09:01
public async Task<DataSet> ExecuteDataSet(string cmdText,string srcTable,CommandType cmdType,string connectionString,
params SqlParameter[] commandparameter)
{
return await Task.Run(() =>
{
using(var ds = new DataSet()) {
ExecuteAdapter(cmdText,cmdType,connectionString,commandparameter).Fill(ds,srcTable);
Dispose();
return ds;
}
});
}

 

我在Task.Run内部直接调用外部的cmdText等参数,很多人都告诉我这样线程不安全,但又没明说,请教下大家 为什么不安全,还有如何改进 谢谢!

再次感谢大家都回答,在各位的指点下,我大致明白所有的Task.Run直接调用外部参数会造成线程不安全的问题。

大致跟第一位兄弟所说一样,如果在获取外部值的时候,外部值不断在变化,这个在线程一直执行下去的时候,确实会造成线程不安全。如以下代码

            var task = NextTask();
            while (task != null)
            {
                Task.Run(() =>
                {
                    Send(task);     //外部调用参数
                });
                task = NextTask();
                //问题就这里,这个task 再次被赋值
                //如果Task内部的Send方法还没执行, 就会造成引用不明确,从而造成线程不安全
            }
~紫鱼~的主页 ~紫鱼~ | 初学一级 | 园豆:2
提问于:2014-08-20 15:14
< >
分享
最佳答案
1
public async Task<DataSet> ExecuteDataSet(string cmdText,string srcTable,CommandType cmdType,string connectionString,
params SqlParameter[] commandparameter)
{
// 如果我在这里添加代码
// 修改上述几个参数
// 这样就会导致线程不安全

return await Task.Run(() =>
{
using(var ds = new DataSet()) {
ExecuteAdapter(cmdText,cmdType,connectionString,commandparameter).Fill(ds,srcTable);
Dispose();
return ds;
}
});
}
收获园豆:15
乐享程序员 | 小虾三级 |园豆:930 | 2014-08-20 15:36

确实 但我这些都是封装好的方法 无法入侵进来的 所以不会有问题

~紫鱼~ | 园豆:2 (初学一级) | 2014-08-20 15:43

@~紫鱼~: 

那些人告诉你那样写不安全的,并不是说你这段代码是不安全的。

而是这种写法会存在上面我说的那种引起线程不安全的情况。

也就是说,他们是从写法上说这样不好,并不是说你这段代码有问题。

乐享程序员 | 园豆:930 (小虾三级) | 2014-08-20 16:33

@螺 丝 钉: 非常感谢你的回答

~紫鱼~ | 园豆:2 (初学一级) | 2014-08-20 16:55
其他回答(4)
0

我觉得“Task.Run内部直接调用外部的cmdText等参数”不存在线程不安全问题

收获园豆:5
dudu | 园豆:30994 (高人七级) | 2014-08-20 16:47

我也是这样认为,所以我来求证,所谓的不安全到底什么?

他们都说要这样来写:

        public async Task<DataSet> ExecuteDataSet(string cmdText, string srcTable, CommandType cmdType,
            string connectionString,
            params SqlParameter[] commandparameter)
        {
            return await Task.Factory.StartNew(obj =>
            {
                using (var ds = new DataSet())
                {
                    var data = (dynamic) obj;
                    ExecuteAdapter(data.cmdText, data.cmdType, data.connectionString, data.commandparameter).Fill(ds, srcTable);
                    Dispose();
                    return ds;
                }
            }, new {cmdText, srcTable, cmdType, connectionString, commandparameter});
        }

 

支持(0) 反对(0) ~紫鱼~ | 园豆:2 (初学一级) | 2014-08-20 16:56

@~紫鱼~: 这和Task.Run没什么区别

支持(0) 反对(0) dudu | 园豆:30994 (高人七级) | 2014-08-20 17:37
0

对于 string 来说,你的写法不存在线程安全问题,因为虽然 string 是引用类型,但是在入栈时的行为同值类型一样。

收获园豆:5
Launcher | 园豆:45045 (高人七级) | 2014-08-20 17:19

感谢,我也是这样认为的,我传递的都是引用类型,不用传参进去

支持(0) 反对(0) ~紫鱼~ | 园豆:2 (初学一级) | 2014-08-20 17:20
0

没看出问题在哪里,区别就是直接RUN 和startNew

 

http://msdn.microsoft.com/zh-CN/library/windows/apps/hh195051.aspx

 

调用StartNew在功能上等效于使用Task.Start 构造函数之一创建任务,然后调用方法以计划执行。

 

翻了点资料

 

startnew 创建并启动任务。

run 将在线程池上运行的指定工作排队,并返回该工作的任务句柄。

字面意思 startnew 直接启动线程执行。

run等线程池有空闲线程再执行。

 

不安全是指等线程池线程的时候?

 

 

 

收获园豆:5
cclient | 园豆:264 (菜鸟二级) | 2014-08-20 17:36

首先感谢你的回答,我也是很纳闷,所以感觉两者区别不是大

支持(0) 反对(0) ~紫鱼~ | 园豆:2 (初学一级) | 2014-08-20 17:38

谢谢!

支持(0) 反对(0) wa3ha | 园豆:151 (初学一级) | 2015-08-05 10:05
0
nanjinff | 园豆:202 (菜鸟二级) | 2014-08-27 14:42

请使用REST风格就可以 实现通信

支持(0) 反对(0) ~紫鱼~ | 园豆:2 (初学一级) | 2014-08-27 18:32
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册