我想触发一个在后台线程上运行的任务.我不想等待任务完成.
在.net 3.5中,我会这样做:
ThreadPool.QueueUserWorkItem(d => { DoSomething(); });
Run Code Online (Sandbox Code Playgroud)
在.net 4中,TPL是建议的方式.我见过的常见模式是:
Task.Factory.StartNew(() => { DoSomething(); });
Run Code Online (Sandbox Code Playgroud)
但是,该StartNew()方法返回一个Task实现的对象IDisposable.推荐这种模式的人似乎忽视了这一点.有关该Task.Dispose()方法的MSDN文档说:
"在释放对任务的最后一个引用之前,始终调用Dispose."
你不能在任务完成之前调用dispose,所以让主线程等待并调用dispose会首先打破后台线程上的操作.似乎也没有任何已完成/已完成的事件可用于清理.
Task类上的MSDN页面没有对此进行评论,并且"Pro C#2010 ..."一书推荐了相同的模式,并且没有对任务处理做出评论.
我知道如果我离开它,终结者最终会抓住它,但当我做了大量的火灾并且忘记了这样的任务并且终结者线程被淹没时,它会回来咬我吗?
所以我的问题是:
Dispose()就Task在这种情况下类?如果是这样,为什么会有风险/后果?Task我错过的物体?我希望能够在WPF ListView中的每个网格列的顶部隐藏标题.
这是我的ListView的XAML:
<Window x:Class="ListViewTest.Test0.ListViewTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Empty ListView Grid" Height="216" Width="435" FlowDirection="LeftToRight" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.IsSharedSizeScope="False">
<Window.Resources>
<XmlDataProvider x:Key="CustomersDS" Source="C:\data.xml"/>
</Window.Resources>
<ListView Margin="0,0,0,50" ItemTemplate="{DynamicResource CustomerTemplate}" ItemsSource="{Binding Source={StaticResource CustomersDS}, XPath=/Customers/Customer}">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding XPath=Code}"/>
<GridViewColumn DisplayMemberBinding="{Binding XPath=Name}"/>
<GridViewColumn DisplayMemberBinding="{Binding XPath=Country}"/>
</GridView>
</ListView.View>
</ListView>
</Window>
Run Code Online (Sandbox Code Playgroud)
我绑定的数据是:
<Customers>
<Customer>
<Code>1234</Code>
<Name>EPI</Name>
<Country>Sesame Street</Country>
</Customer>
<Customer>
<Code>3234</Code>
<Name>Paul</Name>
<Country>United Kingdom</Country>
</Customer>
<Customer>
<Code>3344</Code>
<Name>Juan</Name>
<Country>Spain</Country>
</Customer>
<Customer>
<Code>4321</Code>
<Name>Dodo</Name>
<Country>Mars</Country>
</Customer>
</Customers>
Run Code Online (Sandbox Code Playgroud) 让我们说你有一个在后台线程上运行的简单操作.您希望提供一种取消此操作的方法,以便创建一个布尔标志,您可以从取消按钮的单击事件处理程序设置为true.
private bool _cancelled;
private void CancelButton_Click(Object sender ClickEventArgs e)
{
_cancelled = true;
}
Run Code Online (Sandbox Code Playgroud)
现在您正在从GUI线程设置取消标志,但是您正在从后台线程中读取它.在访问bool之前你需要锁定吗?
你需要这样做(显然也锁定了按钮点击事件处理程序):
while(operationNotComplete)
{
// Do complex operation
lock(_lockObject)
{
if(_cancelled)
{
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
或者这样做是否可以接受(没有锁定):
while(!_cancelled & operationNotComplete)
{
// Do complex operation
}
Run Code Online (Sandbox Code Playgroud)
或者将_cancelled变量标记为volatile.这有必要吗?
[我知道BackgroundWorker类有内置的CancelAsync()方法,但是我对这里的语义和锁定和线程变量访问的使用感兴趣,而不是具体的实现,代码只是一个例子.
似乎有两种理论.
1)因为它是一个简单的内置类型(并且对内置类型的访问在.net中是原子的)并且因为我们只在一个地方写入它并且只在后台线程上读取而不需要锁定或标记为volatile.
2)你应该将它标记为volatile,因为如果你不这样做,编译器可能会优化while循环中的读取,因为它认为它无法修改该值.
哪种方法正确?(为什么?)
[编辑:在这方面似乎有两个明确定义和对立的思想流派.我正在寻找一个明确的答案,所以请尽可能发布您的理由并引用您的消息来源和您的答案.]
我收到了一份样本声明:
MyClass myclass = 3;
Run Code Online (Sandbox Code Playgroud)
怎么可能使这个有效的声明?我需要包含哪些代码MyClass来支持隐式转换int?
以下代码无法编译(使用VS2010),我不明白为什么.编译器应该能够推断出List<TestClass>"兼容"(抱歉缺少一个更好的词)IEnumerable<ITest>,但不知何故它没有.我在这里错过了什么?
interface ITest {
void Test();
}
class TestClass : ITest {
public void Test() {
}
}
class Program {
static void Test(IEnumerable<ITest> tests) {
foreach(var t in tests) {
Console.WriteLine(t);
}
}
static void Main(string[] args) {
var lst = new List<TestClass>();
Test(lst); // fails, why?
Test(lst.Select(t=>t as ITest)); //success
Test(lst.ToArray()); // success
}
}
Run Code Online (Sandbox Code Playgroud)
编译器给出了两个错误:
'ConsoleApplication1.Program.Test(System.Collections.Generic.IEnumerable <ConsoleApplication2.ITest>)'的最佳重载方法匹配有一些无效的参数
参数1:无法从'System.Collections.Generic.List <ConsoleApplication2.TestClass>'转换为'System.Collections.Generic.IEnumerable <ConsoleApplication2.ITest>'
我正在考虑在我正在编写的程序中使用ConcurrentBag,但是我似乎无法在TryTake上找到足够的文档.
我知道该方法可能会失败,但我无法找到可能发生此类失败的情况的解释,以及失败后收集将保留的状态.
如果它只是在另一个线程已经删除了该项目的情况下,那么我不在乎,但我无法承受的是我想要移除的项目仍然在通话后仍然在集合中.
这可能是这样吗?
我在表单中添加了一些控件并更改了Anchor属性我希望它如何工作,但是当我在运行时调整表单大小时,控件保持在同一个位置.
例如,我在表单的右下角有两个按钮 - 它们在表单上,没有容器或类似的东西.Anchor = Bottom,Right.FormBorderStyle =大小.但是当我在运行时拖动调整窗体大小时,按钮不会移动.
我错过了什么吗?
c#2005
我有一个.NET应用程序,它以默认权限作为当前用户运行,然后在某些时候我需要执行一个需要管理员权限的操作.
如何在.NET应用程序中按需获取管理员权限?
要求从一开始就使用管理员权限运行应用程序是不合适的,因为可能不会调用此类操作.
我有两个文本框.一个用于登录ID,另一个用于密码.并且有一个按钮(提交).我需要一个采用登录ID和密码值的事件.即,不点击鼠标我需要调用此事件(只需在键盘上点击'enter').有谁能够帮我!
提前.作者Srini.
在这里,我们有一个SVN存储库,其中包含一个trunk和一个分支,用于在新版本上进行开发.
分支机构即将准备好发布,所以我决定将分支机构重新整合回主干.显然存在一些冲突.包括已在主干中删除的文件中的大量树冲突.
我愉快地解决了所有的冲突并且做了主干.
问题是我们然后对分支进行了一些小的更改,所以我再次重新集成了分支,发生了所有相同的树冲突.解决它们不是问题,但是有很多问题需要一段时间来手动检查和解决它们,我不希望每次进行更改和重新集成时都要经历相同的解决过程.我曾期望SVN认识到该分支已经重新整合一次,并且只是从最后一次重新整合发生的那一点开始合并.
当我打开修订图时,它显示了主干和分支被拆分的点,但它没有显示合并.应该是?
服务器:WinServer2003(R2sp2),VisualSVNServer(1.7.2).客户端:WindowsXP(sp3),我一直在使用TortoiseSVN(1.6.5)来完成所有这些工作,但我也安装了命令行客户端.
我通过确保我的主干是最新的,并使用TortoiseSVN进行合并来进行合并,并在选择对话框时选择"重新整合分支".我将合并深度设置为"工作副本"
我是否错误地处理了这种情况?我应该采取不同的做法吗?
(也许我们的存储库布局有误.我们从trunk中分支,对分支中的新版本进行了所有更改,现在发布是因为我们正在将分支合并回到trunk.也许这是错误的方法,我已经阅读了一些人反过来做的事情,在主干中进行所有更改,并且只在你准备好发布并且分支成为受支持的发行版本时才进行分支)
c# ×7
.net ×6
winforms ×2
.net-4.0 ×1
admin-rights ×1
anchor ×1
branch ×1
collections ×1
concurrency ×1
covariance ×1
dispose ×1
elevation ×1
forms ×1
generics ×1
gridview ×1
listview ×1
locking ×1
merge ×1
svn ×1
tortoisesvn ×1
uac ×1
wpf ×1
wpf-controls ×1