C#如何取消执行方法

时间:2015-06-09 04:13:59

标签: c# multithreading delegates thread-safety

我有一个委托方法在我的应用程序中运行繁重的进程(我必须使用MS Framework 3.5):

private delegate void delRunJob(string strBox, string strJob);

执行:

    private void run()
    {
        string strBox = "G4P";
        string strJob = "Test";

        delRunJob delegateRunJob = new delRunJob(runJobThread);
        delegateRunJob.Invoke(strBox, strJob);
    }

方法的某些部分runJobThread

我调用外部程序(SAP - 远程函数调用)来检索数据。执行该行可能需要1-30分钟。

private void runJobThread(string strBox, string strJob)
{
    // CODE ...
    sapLocFunction.Call(); // When this line is running I cannot cancel the process
    // CODE ...
}

我想让用户取消整个过程。

怎么能实现这个目标?我尝试了一些方法;但我陷入了同样的境地;当这条特定的线路运行时,我无法停止这个过程。

4 个答案:

答案 0 :(得分:6)

您必须研究异步和等待机制,而不是使用委托机制。当您了解此机制后,您可以转到canceltoken。 可以在这里找到做这两件事的例子: http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx

答案 1 :(得分:1)

好;我找到了解决问题的复杂但有效的方法:

a。)我创建了一个" Helper应用程序"在流程运行时显示通知图标(确保不会干扰主应用程序的正常执行):

private void callHelper(bool blnClose = false)
{
    if (blnClose)
        fw.processKill("SDM Helper");
    else
        Process.Start(fw.appGetPath + "SDM Helper.exe");
}

b。)我创建了一个只调用繁重生产线的线程。

c。)当线程处于活动状态时,我会检查名为&#34的外部文件;取消" (" Helper应用程序"这样做;当用户单击一个选项取消Helper创建文件的过程时)。

d。)如果存在文件;处理所有对象并打破while循环。

e。)方法sapLocFunction.Call()将引发异常,但我预计会出错。

private void runJobThread(string strBox, string strJob)
{
    // CODE ...

    Thread thrSapCall = new Thread(() =>
    {
        try { sapLocFunction.Call(); }
        catch { /* Do nothing */ }
    });

    thrSapCall.Start();

    while (thrSapCall.IsAlive)
    {
        Thread.Sleep(1000);
        try
        {
            if (fw.fileExists(fw.appGetPath + "\\cancel"))
            {
                sapLocFunction = null;
                sapLocTable = null;
                sapConn.Logoff();
                sapConn = null;
                canceled = true;
                break;
            }
        }
        finally { /* Do nothing */ }
    }

    thrSapCall = null;

    // CODE ...
}

像魅力一样!

答案 2 :(得分:0)

我认为你必须采用方法described here。阅读帖子,了解为什么这距离理想还有很长的路要走。 也许这可能有用......

private void runJobThread(string strBox, string strJob, CancellationToken token)
{
   Thread t = Thread.CurrentThread;
    using (token.Register(t.Abort))
    {
    // CODE ...
    sapLocFunction.Call(); // When this line is running I cannot cancel the process
    // CODE ...
   } 
}

答案 3 :(得分:0)

一点dnspy在nco3.0上公开了cancel方法。

    private readonly static Type RfcConnection = typeof(RfcSessionManager).Assembly.GetType("SAP.Middleware.Connector.RfcConnection");
    
    private readonly static Func<RfcDestination, object> GetConnection = typeof(RfcSessionManager).GetMethod("GetConnection", BindingFlags.Static | BindingFlags.NonPublic).CreateDelegate(typeof(Func<RfcDestination, object>)) as Func<RfcDestination, object>;
    
    private readonly static MethodInfo Cancel = RfcConnection.GetMethod("Cancel", BindingFlags.Instance | BindingFlags.NonPublic);


    object connection = null;
    var completed = true;
    
    using (var task = Task.Run(() => { connection = GetConnection(destination); rfcFunction.Invoke(destination); }))
{  
    try
    {
         completed = task.Wait(TimeSpan.FromSeconds(invokeTimeout));
    
         if (!completed)
             Cancel.Invoke(connection, null);                            
                                
         task.Wait();
    }
    catch(AggregateException e)
    {
         if (e.InnerException is RfcCommunicationCanceledException && !completed)
             throw new TimeoutException($"SAP FM {functionName} on {destination} did not respond in {timeout} seconds.");
         throw;
    }   
}