【问题标题】:Cancel multi-threading Tasks including running .dll取消多线程任务,包括运行.dll
【发布时间】:2019-12-02 05:50:12
【问题描述】:

我有 2 个同步启动的不同任务。其中之一是我调用 .dll 来创建 COM 对象(编写 Excel 文件)的方法。当我终止这两个任务时,Excel 文件仍在使用中,所以我无法删除它。这就是我调用这两个任务的方式:

private CancellationTokenSource cancel_1 = new CancellationTokenSource();
private CancellationTokenSource cancel_2 = new CancellationTokenSource();

    private void Form1_Load(object sender, System.EventArgs e)
    {
        cancel_1 = new CancellationTokenSource();
        var task_1 = Task.Factory.StartNew(() => DoWork1(), cancel_1.Token);

        //2nd task
        cancel_2 = new CancellationTokenSource();
        var task_2 = Task.Factory.StartNew(() => DoExcelWork(), cancel_2.Token);
    }

然后我尝试在 form_closure 中取消这两个任务:

private void Form1_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e)
{
   //Cancel all running processes
   cancel_1.Cancel();
   cancel_2.Cancel();

   // I've also set a variable for check if Task_2 is running and try to clear COM 
   // object with clearing GC(), but It's not working
   if (excel_running)
   {
       GC.Collect();
       GC.WaitForPendingFinalizers();
       GC.Collect();
       GC.WaitForPendingFinalizers();

       string filename = Environment.GetFolderPath(Environment.SpecialFolder.Desktop).ToString() + @"\" + "sample.xlsx";
       File.Delete(filename)

   }
}

但是,这不会终止 .dll 为写入 Excel 文件而启动的进程。我注意到在后台运行的进程是“COM 代理”,所以正如你所见,我尝试在 2 个周期内清理 GC(),但文件仍在使用中。

我在线程中的方法代码是这样的:

public void DoExcelWork()
{
    try
    {
        using (var con = new OracleConnection(conn_string))
        {
            con.Open();

            using (OracleCommand cmd = new OracleCommand("myprocedure"))
            {
                cmd.Connection = con;
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.Parameters.Add(new OracleParameter("par1", OracleDbType.NVarchar2) { Direction = ParameterDirection.Input, Value = SQL_string });

                cmd.Parameters.Add(new OracleParameter("result", OracleDbType.RefCursor)).Direction = ParameterDirection.Output;

                //Here is the call of .dll             
                Export export_xml = new Export();
                export_xml.Save_to_Excel(cmd);

                excel_running = false;

                if (cancel_2.IsCancellationRequested)
                {
                   cmd.Cancel();
                   return;
                }

    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message + "in " + ex.StackTrace);
    }
}

我的问题是 - 如何正确取消后台进程,以便即使运行 .dll 也会关闭?

【问题讨论】:

  • 您使用的取消源错误。您需要定期检查取消状态,如果已请求取消,您需要自己处理。 excel类有可以调用的cancel方法吗?
  • @the.Doc,对不起,我忘了粘贴我在 DoExcelWork() 中检查请求取消的方式,我现在编辑了。至于 .dll - 不,我没有任何取消方法。我应该添加它以及如何添加?
  • save_to_excel 是阻塞调用吗?除了 oracle cmd,它在内部做什么可以取消?
  • @the.Doc,没有其他东西可以在内部取消。 “cmd”被传递给 .dll,然后所有逻辑都从那里完成 - 它从 DB 中获取数据并写入 Excel 文件。我是否应该在 save_to_excel 中添加令牌参数,并在 .dll 中添加“token.IsCancellationRequested etc.”并关闭那里的所有内容,这样行吗?
  • 是否可以将您的代码从 Office COM 互操作移动到更现代的Open XML SDK,Microsoft 为处理使用“.xlsx”扩展名的 Office 文件提供了这种方式?这可能有助于解决您的很多问题,因为 Open XML SDK 不需要打开 Excel 实例,它可以直接操作文件。

标签: c# excel asynchronous com task


【解决方案1】:

解决了。我不得不重新组织 DoExcelWork() 方法以接受 CancellationToken 的附加参数,然后在调用“token.IsCancellationRequested”的方法内关闭所有正在创建 Excel 文件的对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多