0

3 つのスレッドで 3 つの異なる関数を呼び出しており、3 つのスレッドからのすべての戻り値を追加する必要があります。

私が試したのは

    Thread t1 = new Thread(() => response.Candidate = AddCandidate2Daxtra(request, args));
    t1.Start();

    Thread t2 = new Thread(() => response.Candidate.HRXML = parsecv(profile));
    t2.Start();

    Thread t3 = new Thread(() => response.Candidate.Attachments.Add(Print2Flash(alias, bytes, args)));
    t3.Start();

    while (t1.IsAlive == true || t2.IsAlive == true || t3.IsAlive == true)
    {
        Thread.Sleep(1000);
    }

しかし、最後に最初のスレッド値のみを取得しています.残りの2つのスレッド値を取得していません. 誰でも私を助けてください問題は何ですか?

前もって感謝します。

4

4 に答える 4

3

スレッドが終了する順序がわからないため、競合状態になります。

スレッドごとに個別のローカル変数を使用します。これは、先ほど で行った方法と同様に、スレッド コンストラクター内で割り当てますresponse

次に、次を使用してすべてのスレッドを待ち.Join()ます。

t1.Join();
t2.Join();
t3.Join();

response次に、すべてのJoin()呼び出しが返された後に、ローカル変数を使用して設定します。

ただし、代わりにタスクを使用します。これが例です。これは、それぞれ異なる戻り値の型を持つ 3 つの異なるメソッドを別々のスレッドで実行します。

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    class Program
    {
        private void run()
        {
            // Using tasks directly:

            var task1 = Task<int>.Factory.StartNew(methodOne);
            var task2 = Task<string>.Factory.StartNew(methodTwo);
            var task3 = Task<double>.Factory.StartNew(methodThree);

            // Alternatively:
            // var task1 = Task.Run(new Func<int>(methodOne));
            // var task2 = Task.Run(new Func<string>(methodTwo));
            // var task3 = Task.Run(new Func<double>(methodThree)); 

            string result = string.Format
            (
                "Task 1: {0}, Task 2: {1}, Task 3: {2}",
                task1.Result, // Accessing Task.Result automatically
                task2.Result, // waits for the task to complete.
                task3.Result 
            );

            Console.WriteLine(result);

            // Alternatively, you can use tasks indirectly via Parallel.Invoke().
            // You might find this more readable and less typing:

            int    r1 = 0;
            string r2 = null;
            double r3 = 0;

            Parallel.Invoke
            (
                () => r1 = methodOne(),
                () => r2 = methodTwo(),
                () => r3 = methodThree()
            );

            result = string.Format
            (
                "Task 1: {0}, Task 2: {1}, Task 3: {2}",
                r1,
                r2,
                r3
            );

            Console.WriteLine(result);
        }

        static int methodOne()
        {
            Thread.Sleep(1000);
            return 1;
        }

        static string methodTwo()
        {
            Thread.Sleep(750);
            return "two";
        }

        static double methodThree()
        {
            Thread.Sleep(500);
            return 3.0;
        }

        static void Main(string[] args)
        {
            new Program().run();
        }
    }
}

どちらのアプローチを取るにしても、重要なことは、結果をスレッドまたはタスク内に直接割り当てないことです。responseすべてのスレッドまたはタスクが終了するまで待ってから、結果を に割り当ててresponseください。

于 2013-10-01T12:09:55.303 に答える
0

問題はそれである可能性がありt2、完了t3に依存しています。とが前に終了したt1場合、それらの結果は の古いインスタンスに注入されます。この依存関係を壊す必要があります。t2t3t1Candidate

次のコードを検討してください。

var t2 = Task.Factory.StartNew(() => parsecv(profile));
var t3 = Task.Factory.StartNew(() => Print2Flash(alias, bytes, args));
response.Candidate = AddCandidate2Daxtra(request, args);
response.Candidate.HRXML = t2.Result;
response.Candidate.Attachments.Add(t3.Result);

ここで行っているのは起動t2t3非同期であり、それらが完了すると、戻り値Taskが作成されたインスタンスに格納されます。それまでの間、元々あったものはt1メイン スレッドで同期的に実行されるようになりました。この作業を行うために新しいスレッドを作成しても意味がありません。メインスレッドにそれを実行させるだけです。そうしないと、とにかくアイドル状態になります。が完了AddCandidate2Daxtraすると、その構成値を取得しTask.Resultて割り当てることができます。プロパティはTask.Result、タスクが完了するまでブロックします。

これを行うには他にもさまざまな方法がありますが、ほとんどは上記のようにエレガントで読みやすいものではありません。利用できない場合Taskは、コメントでお知らせください。回答を更新して、TPL に適していない方法を含めます。

于 2013-10-01T14:33:47.127 に答える
0

これは、スレッドが と の後にt1スケジュールされているために発生します。次のようにコードを書き直すことができます。t2t3

    Thread t1 = new Thread(() => response.Candidate = AddCandidate2Daxtra(request, args));
    t1.Start();
    t1.Join();

    Thread t2 = new Thread(() => response.Candidate.HRXML = parsecv(profile));
    t2.Start();

    Thread t3 = new Thread(() => response.Candidate.Attachments.Add(Print2Flash(alias, bytes, args)));
    t3.Start();

    while (/*t1.IsAlive == true || */t2.IsAlive == true || t3.IsAlive == true)
    {
        Thread.Sleep(1000);
    }
于 2013-10-01T12:13:00.883 に答える
0

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

// get all the data you need separately
Candidate candidate = null; // no idea of the real type

Thread t1 = new Thread(() => candidate = AddCandidate2Daxtra(request, args));
t1.Start();

HRXML HRXML = null; // no idea of the real type

Thread t2 = new Thread(() => HRXML = parsecv(profile));
t2.Start();

Attachment att = null; // no idea of the real type

Thread t3 = new Thread(() => att = Print2Flash(alias, bytes, args));
t3.Start();

while (t1.IsAlive || t2.IsAlive || t3.IsAlive)
{
    Thread.Sleep(1000);
}

そして、すべてが完了したら:

response.Candidate = candidate;
candidate.HRXML = HRXML;
response.Candidate.Attachments.Add(att);
于 2013-10-01T12:18:20.697 に答える