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方法还没执行, 就会造成引用不明确,从而造成线程不安全 }
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等参数”不存在线程不安全问题
我也是这样认为,所以我来求证,所谓的不安全到底什么?
他们都说要这样来写:
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}); }
@~紫鱼~: 这和Task.Run没什么区别
对于 string 来说,你的写法不存在线程安全问题,因为虽然 string 是引用类型,但是在入栈时的行为同值类型一样。
感谢,我也是这样认为的,我传递的都是引用类型,不用传参进去
没看出问题在哪里,区别就是直接RUN 和startNew
http://msdn.microsoft.com/zh-CN/library/windows/apps/hh195051.aspx
其取消标记是 CancellationToken.None。
它使用默认任务计划程序。
调用StartNew在功能上等效于使用Task.Start 构造函数之一创建任务,然后调用方法以计划执行。
翻了点资料
startnew 创建并启动任务。
run 将在线程池上运行的指定工作排队,并返回该工作的任务句柄。
字面意思 startnew 直接启动线程执行。
run等线程池有空闲线程再执行。
不安全是指等线程池线程的时候?
首先感谢你的回答,我也是很纳闷,所以感觉两者区别不是大
谢谢!