2

このようにシンプル!これは私の試みであり、スレッド化する関数は、一時停止可能なセクションでそれ自体を介してPause()関数を使用する必要があります。

using System;
using System.Threading;

class BlackThread {
    private bool paused;
    private Thread innerThr;

    // ---

    public bool IsAlive {
        get {
            return innerThr.IsAlive;
        }
    }

    // ===

    public void SetAndGo (ThreadStart start) {
        paused = false;

        innerThr = new Thread(start);
        innerThr.Start();
        WaitForIt();
    }

    // ---

    public void Pause() {
        paused = true;
        while (paused);
    }

    public void Unpause() {
        paused = false;
    }

    public void WaitForIt() {
        while(!paused && IsAlive);
    }

    public void Continue() {
        Unpause();
        WaitForIt();
    }
}

class MainClass {
    static void pausableFunction (BlackThread self) {
        Console.WriteLine("* Waiting...");
        self.Pause();
        Console.WriteLine("* Doing stuff.");
        self.Pause();
        Console.WriteLine("* Finished!");
    }

    static void Main() {
        BlackThread noir = new BlackThread();
        noir.SetAndGo(() => pausableFunction(noir));

        while (noir.IsAlive) {
            Console.Write("> ");
            Console.ReadKey();
            noir.Continue();
        }
    }
}

残念ながら、これはいつでも一時停止できるものではなく、外部処理を続行できるようになるまで待機する必要がある関数のスレッドです。ゲームの暴徒によるアクションのように、フレームを描画ループで描画してから続行する必要があり、暴徒のAIはゲームのメインループで処理されます。

ある種の疑似スレッドになると思いますか?ともかく。

これにより、暴徒はAIでチェックをカスケードする代わりに、ループごとにこのアクションを少しずつ処理できるようになります...

if mob is doing action {
    if mob has already done this previous part of the action {
        do the following part
    }
}

...スレッドでは、このようになります:

do the first step of the action
Wait for it to be rendered...
do the following step of the action
Wait for it to be rendered...
do the last step of the action
(Action ends here, no need to wait for anything anymore)

今、私の実装には修正方法がわからないバグがあります。BlackThreadの一時停止を解除することになっている場合、BlackThreadを使用する関数(この場合はpausableFunction())で一時停止されたままになります。インスタンスがどのように渡されるかによると思いますか?

それが私が推測しているものである場合、つまり、何か(そしてブール値が一時停止していると思います)が参照ではなく値によって渡される場合、どうすれば修正できますか?

私はCとC++のポインターに本当に慣れているので、スコープ間のオブジェクトの値の通信をC#で処理するときに、少し絡まることがあります。


これは、動作するコードのバージョンであり、次のようなプロトタイプです。

using System;
using System.Threading;

class Program {
    static bool paused;

    static void Pause() {
        paused = true;
        while (paused);
    }

    static void Unpause() {
        paused = false;
    }

    static void WaitForIt(Thread waited) {
        while(!paused && waited.IsAlive);
    }

    static void Continue (Thread ToStop) {
        Unpause();
        WaitForIt(ToStop);
    }

    static void SetAndGo (out Thread thread, ThreadStart Start) {
        thread = new Thread(Start);
        thread.Start();
        WaitForIt(thread);
    }

    // ---

    static void thr (string chant) {
        // Console.WriteLine("Waiting...");
        // Pause();
        // Console.WriteLine("{0}", chant);
        // Pause();
        // Console.WriteLine("Well, I'm finished!");

        Console.WriteLine("I'm finished!");
    }

    static void Main() {
        // Thread tt = new Thread(() => thr());
        // tt.Start();
        // WaitForIt(tt);

        Thread tt;
        SetAndGo(out tt, (() => thr("I'm doing stuff.")));

        while (tt.IsAlive) {
            Console.Write("> ");
            Console.ReadKey();
            Continue(tt);
        }
    }
}

読みやすさも向上させるために、特定のクラスをすべて担当したいので、使用していません。

4

1 に答える 1

1

さて、私はすでに試していたことを達成したので、今後の参考のためにコードをここに残しておきます!

最後に、これは BlackThread クラスです。

using System;
using System.Threading;

class BlackThread { 
    //* ===== *//

    private AutoResetEvent pauser = new AutoResetEvent(false);
    private AutoResetEvent waiter = new AutoResetEvent(false);

    private Thread innerThr;

    // ----- //

    public bool IsActing {
        get {
            if (innerThr != null) return innerThr.IsAlive;
            else return false;
        }
    }

    //* ===== *//

    public void KickStart_(ThreadStart start) {
        innerThr = new Thread(start);
        innerThr.Start();

        WaitForIt();
    }

    // ----- //

    // FOR THE THREADED FUNCTION
    public void Wait() {
        waiter.Set();
        pauser.WaitOne();
    }

    public void End() {
        waiter.Set();
    }

    // ----- //

    // FOR BLACKTHREAD MANAGING
    private void WaitForIt() {
        waiter.WaitOne();
    }

    public void Continue() {
        if (IsActing) {
            pauser.Set();
            WaitForIt();
        }
    }

    //* ===== *//
}

そして、ここにその使用例があります:

class MainClass {
    static void pausableFunction() {
        Console.WriteLine("* Waiting...");

        Event.Wait();

        Console.WriteLine("* Doing stuff.");
        Thread.Sleep(1000);

        Event.Wait();

        Console.WriteLine("* Finished!");

        Event.End();
    }

    static void anotherFunction(int foo) {
        Console.WriteLine("* Wanna know the value of a number?");

        Event.Wait();

        Console.WriteLine("* I'll tell you. It's {0}!", foo);

        Event.End();
    }

    static void simpleFunction() {
        Console.WriteLine("* I'm done already!");
    }

    static BlackThread Event = new BlackThread();   
    static Random Rand = new Random();

    static void Main() {        
        int r;

        do {
            if (!Event.IsActing) {
                Console.WriteLine();
                r = Rand.Next(3);

                if (r == 0) {
                    Event.KickStart_(() => pausableFunction());
                }
                else if (r == 1) {
                    simpleFunction();
                }
                else {
                    Event.KickStart_(() => anotherFunction(Rand.Next(20) + 1));
                }
            }
            else {
                Event.Continue();
            }

            Console.Write("> ");
            Console.ReadKey();
        } while(true);
    }
}

最終的に使用することにしたのは、2 つの AutoResetEvent ハンドラです。1 つは、一時停止を必要とするスレッドの関数で管理され、メイン ループのウェイター ARE を一時停止します。もう 1 つは、メイン ループで管理され、BlackThread をサポートする関数でスレッドを一時停止する一時停止 ARE です。つまり、BlackThread インスタンスにアクセスできます。

この場合、静的な BlackThread オブジェクトを使用しましたが、パラメーターとして関数に渡すこともできます。

そして、はい、それは仏教の地獄にちなんで名付けられました!

于 2012-11-25T21:50:45.820 に答える