0

{ここに任意の種類のサービスを挿入}からデータを取得するために、ユーザーがカスタマイズ可能な間隔で複数のスレッドを生成するアプリに取り組んでいます。私のアプリはCMDスクリプトを使用し(つまり、Windowsがコンホストを生成します)、ネットワークドライブをマッピングすることもあります。その後、カスタマイズされた間隔でスリープし、繰り返します。それらをカウンターと呼びましょう。

これまでのところ良好ですが、非同期で実行できないプロシージャ(ドライブのマッピングなど)がいくつかあるため、プログラムが正常に動作するように、特定のスレッドに対して何らかのキューを作成する必要があります。

これまでのところ、ここにあるこのプロデューサー/コンシューマーキューのブログ投稿を使用して実装することができました-> http://moazzam-khan.com/blog/?p=418。これはCMDカウンターで機能するため、7821678321がPCをホストしてブロックするようにアプリが生成されることはなく、キューに入れています。とにかく、それは私が問題を抱えていることではありません。

いくつかのコマンドを実行してマップを解除し、次のスレッドを実行させるためにネットワークドライブをマップする必要がある場合、問題が発生します。問題をより明確に説明しましょう。

スレッドタイプA:キューに入れる必要があるだけです(Aタイプのみ)。Bタイプのスレッドが実行されるのを待つ必要も、実行を終了する必要もありません。これは、チュートリアルにあるコードを使用して実際に実行されます。

スレッドタイプB:他のBタイプのスレッドは、現在のBタイプのスレッドが実行を終了するのを待つ必要があります。

Bタイプのスレッドにも同じチュートリアルを使用することを考えていましたが、他のスレッドがブロックが解除されるまで自分自身を呼び出し続け、自分自身を呼び出すとドライブが再マップされて機能しないため、使用できないことに気付きました(argh 、ドライブがマップされているかどうかはわかりますが、どこにマップされているかはわかりません...できますが、書き込みを避けたい不要なコードです)。

私は宿題をしてグーグルを調べ、C#でlockキーワードを使用してエクササイズを試す小さなアプリを作成しましたが、関数が他のスレッドをブロックしていても、ブロック関数を呼び出し続けているので、それは望ましくありません:(

そこにはたくさんのチュートリアルがありますが、私がそれらを理解するのに十分なほど簡潔で的確なものはありません。ここSOでいくつかの質問を見つけましたが、それらは主にJava関連であり、C#4.0で作業しています。

さて、これが私が書いたコードです。これを実行すると、他のスレッドがブロッキング関数を呼び出すことに気付くでしょう。関数を呼び出した最初のスレッドが終了するまで、関数を呼び出さないでください。それか、ある種のキューを作成しますが、他のスレッドがプロセスを実行するのに時間がかかったために、キューがいっぱいになるのを避けます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ThreadTest
{
    public class BlockObj
    {
        Object lockObj = new Object();

        public void DoBlock(int id)
        {
            lock (lockObj)
            {
                Console.WriteLine("Counter " + id + " locking object created, wait 5 sec");
                Thread.Sleep(5000);
                Console.WriteLine("Stuff done, keep going");
            }
        }
    }

    class Program
    {
        static Random r = new Random(DateTime.Now.Second);
        static BlockObj oo = new BlockObj();

        public static void Counter(object id)
        {
            int i = (int)id;
            while (true)
            {
                Thread.Sleep(1000 * r.Next(1, 10));
                Console.WriteLine("Counter " + i + " call blocking stuff...");
                oo.DoBlock(i);
                Console.WriteLine("Counter " + i + " finish work");
            }
        }

        public static void Main(string[] args)
        {
            for (int i = 0; i < 5; i++)
            {
                Thread t = new Thread(new ParameterizedThreadStart(Counter));
                t.Start(i);
            }
        }
    }
}

実際、2つのスレッドキューを生成するアプリの概念実証コードを確認したいと思います。これらのキュー内のスレッドは、現在のスレッドの実行が終了するのを待ってから、次のスレッドを実行します。ただし、各キューには独自のブロッキングがあります。スレッドキュー1は、スレッドキュー2の実行とその逆をブロックしてはなりません。

4

1 に答える 1

0

さて、私は自分のコードでそれを解決し、うまくいくまでいろいろ試してみました:)。

同期された単純なキューが必要な場合は、次のとおりです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Collections;
using System.Runtime.Remoting.Messaging;

namespace TheadingPool1
{
    // http://www.c-sharpcorner.com/UploadFile/mgold/QueueInThread11222005232529PM/QueueInThread.aspx

    public class ThreadQueue
    {
        private Queue _qOrder = new Queue();
        private Queue _qSync;
        private Thread _qThread;
        private ManualResetEvent _eWait = new ManualResetEvent(false);

        private int _wait;

        public ThreadQueue(int w)
        {
            _wait = w;
            _qSync = Queue.Synchronized(_qOrder);
        }

        public void Start()
        {
            _qThread = new Thread(new ThreadStart(Process));
            _qThread.IsBackground = true;
            _qThread.Start();
        }

        public void Process()
        {
            Random x = new Random(DateTime.Now.Second);
            object item;
            while (true)
            {
                item = null;
                lock (_qSync.SyncRoot)
                {
                    if (_qSync.Count > 0)
                    {
                        item = (object)_qSync.Dequeue();
                    }
                    else
                    {
                        _eWait.Reset();
                    }
                }
                if (item != null)
                {
                    Console.WriteLine("[" + _wait + "] [" + item.ToString() + "] :D");
                    Thread.Sleep(_wait * x.Next(1, 5));
                }
                else
                {
                    _eWait.WaitOne();
                }
            }
        }

        public void Enqueue(object obj)
        {
            _qSync.Enqueue(obj);
            _eWait.Set();
        }
    }

    public class Program
    {
        private static ThreadQueue _q1 = new ThreadQueue(10);
        private static ThreadQueue _q2 = new ThreadQueue(50);

        public static void Main(string[] args)
        {
            _q1.Start();
            _q2.Start();

            for (int i = 0; i < 50; i++)
                _q1.Enqueue(i);

            for (int i = 0; i < 50; i++)
                _q2.Enqueue(i);

            while (true)
            {
                Thread.Sleep(100);
            }
        }
    }
}
于 2013-01-24T16:04:59.117 に答える