1

私のWPFアプリケーションには、BlueBeamQServerを使用してファイルをPDFに変換する長時間実行プロセスがあります。プロセスが行われるとき、それはフリーズするべきではないので、以下のコードはそれを処理するために書かれています:

private void btn_convert_Click(object sender, RoutedEventArgs e)
{
        thread = new Thread(new ThreadStart(WorkerMethod));
        thread.SetApartmentState(ApartmentState.STA);
        thread.IsBackground = true;
        thread.Name = "PDF";
        thread.Start();
}

WorkerMethod()
{
//code to connect to Q server and conversion goes here
}

これで、プロセスが開始されると、キャンセルボタンがユーザーに表示されます。ユーザーがキャンセルを押したら、開始したスレッドを中止したいと思います。私は以下のようにコードを書きました:

private void btn_cancel_Click(object sender, RoutedEventArgs e)
    {
        if (thread.Name == "PDF")
            thread.Abort(); 
    }

ただし、スレッドは中止せず、プロセスを続行します。貴重なご提案をお願いします。

4

3 に答える 3

4

Abort可能な限り避けるべきです。スレッドを適切にキャンセルする方法については、SOを検索してください。これは、サードパーティのライブラリメソッドなど、影響を与えられない他のコードをスレッドコードが呼び出す場合には実行できません。

たとえば、スレッドメソッドが次のようなことを行う場合:

WorkerMethod()
{
    CallFunctionInExternalDLL();
}

正しく中止することはできません。

このようなスレッドを「キャンセル」するには、キャンセルする必要があることをスレッドに示し(boolたとえば、フラグを使用して)、スレッドに結果をロールバックさせる(たとえば、作成されたPDFなどを削除する)のが最善です。その後、アプリケーションは、スレッドが開始されていないかのように続行できます。

たとえば、コードは次のようになります。

WorkerMethod()
{
    CallFunctionInExternalDLL();
    if (m_threadAborted)
        RollBackWhatFunctionDid();
}

スレッドが次のようになっている場合:

WorkerMethod()
{
    while (true)
    {
        CallFunctionInExternalDLL();
    }
}

あなたはこれを行うことができます:

WorkerMethod()
{
    while (!m_threadAborted)
    {
        CallFunctionInExternalDLL();
    }

    if (m_threadAborted)
        RollBackStuff();
}

これらの例でm_threadAbortedは、は次のboolように宣言されたフラグです。

private volatile bool m_threadAborted = false;
于 2013-03-26T12:55:48.927 に答える
1

スレッドの代わりにBackgroundworkerを使用でき、コードにループが含まれている場合はキャンセルできます(各ループでブール型プロパティをテストする必要があります)

// define the backgroundWorker
this.backgroundWorker.DoWork += new DoWorkEventHandler(this.BackgroundWorker_DoWork);
this.backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.BackgroundWorker_RunWorkerCompleted);
this.backgroundWorker.WorkerSupportsCancellation = true;

// execute process
this.backgroundWorker.RunWorkerAsync();

// cancel process
this.backgroundWorker.CancelAsync();

そしてBackgroundWorker_DoWorkのコードで:

// in a loop
if (this.backgroundWorker.CancellationPending == false)
{
...
}
于 2013-03-26T12:55:41.557 に答える
1

ここで説明されているように、CancellationTokenSourceを使用できます:http:
//msdn.microsoft.com/en-us/library/dd997364.aspx?cs-save-lang = 1&cs-lang = csharp#code-snippet-1

static void CancelWithThreadPoolMiniSnippet()
{

//Thread 1: The Requestor 
// Create the token source.
CancellationTokenSource cts = new CancellationTokenSource();

// Pass the token to the cancelable operation.
ThreadPool.QueueUserWorkItem(new WaitCallback(DoSomeWork), cts.Token);

// Request cancellation by setting a flag on the token.
    cts.Cancel();
}

//Thread 2:The Listener 
static void DoSomeWork(object obj)
{
    CancellationToken token = (CancellationToken)obj;
    for (int i = 0; i < 100000; i++)
    {
        // Simulating work.
        Thread.SpinWait(5000000);

        if (token.IsCancellationRequested)
        {
            // Perform cleanup if necessary. 
            //... 
            // Terminate the operation. 
            break;
        }
    }
}

この投稿では、他の可能な方法について説明
します。.NETでスレッドをクリーンに終了することに関する質問

于 2013-03-26T13:04:32.147 に答える