1

スレッドについて質問があります。複数のクライアントと接続するマルチスレッド TCP アプリケーションを取得しました。スレッドには、かなり時間がかかる操作があります。(多分1分かそこら)。たとえば、実行中のスレッドが 1 つだけの場合、遅延を設定せずにすべてのスレッドに同じ時間を与えるには、スリープをどのように設定すればよいですか?

while(CanDoSomething)
{
    DoIt();                  //Can take all from a few seconds to a few minutes
    Thread.Sleep(100);
}

これは睡眠を行うための最良の方法ですか?それとももっと長い睡眠時間を与えるべきですか?他のスレッドは 100 ミリ秒しか取得できませんか?それとも開始して終了する時間を与えますか? あるスレッドが他のスレッドよりもはるかに速く作業を完了できると感じているため...すべてのスレッドが同じ優先度で確実に作業を完了できるようにするためにできることは他にありますか?

編集、その他のコード:

private void ListenForClients()
    {
        try
        {

            this.tcpListener.Start();
            while (true)
            {
                TcpClient client = this.tcpListener.AcceptTcpClient();

                Connection c = new Connection(this.parent);
                connectionCollection.Add(c);
                Thread clientThread = new Thread(new ParameterizedThreadStart(c.HandleClientComm));

                threadCollection.Add(clientThread);
                clientThread.Start(client);
            }
        }
        catch (Exception e)
        {
        }
    }
public Connection()
    {
        this.todo = new ArrayList();
        todoT = new Thread(handleToDo);
        todoT.Start();
    }

 public void HandleClientComm(object client)
    {
        try
        {

            TcpClient server = (TcpClient)client;

            NetworkStream ns = server.GetStream();
            byte[] data = new byte[1024];
            string input, stringData;
            online = true;
            DateTime lastTime = DateTime.Now;

            while (true && this.online)
            {
                try
                {
                    if (lastTime.AddMinutes(2) < DateTime.Now)
                        break;

                    data = new byte[1024];
                    if (ns.DataAvailable && ns.CanRead)
                    {
                        int recv = ns.Read(data, 0, data.Length);
                        if (recv > 0)
                        {
                            lastTime = DateTime.Now;
                            if ((byte)data[recv - 1] == (byte)255)
                            {
                                int cnt = -1;
                                for (int i = 0; i < recv; i++)
                                {
                                    if (data[i] == (byte)254)
                                    {
                                        cnt = i;
                                        break;
                                    }
                                }

                                int nr = recv - cnt - 2;
                                byte[] tmp = new byte[nr];

                                for (int i = 0; i < nr; i++)
                                {
                                    tmp[i] = data[cnt + i + 1];
                                }
                                string crc = Encoding.UTF8.GetString(tmp);
                                stringData = Encoding.UTF8.GetString(data, 0, cnt);

                                MsgStruct msgs = new MsgStruct(stringData);
                                msgs.setCrc(crc);
                                Thread.Sleep(200);

                                addTodo(msgs);
                                if (msgs.getMsg()[0] == 'T' && this.type == 1)
                                    this.parent.cStructHandler.sendAck(msgs, this.ID);
                                Console.WriteLine(todo.Count);

                            }
                        }
                    }
                    if (parent.cStructHandler.gotMsg(this.ID))
                    {
                        MsgStruct tmpCs = parent.cStructHandler.getNextMsg(this.ID);

                        if (tmpCs.getMsg().Length != 0 && ns.CanWrite)
                        {
                            byte[] ba = Encoding.UTF8.GetBytes(tmpCs.getMsg());

                            if (tmpCs.getCrc() == "")
                            {
                                ulong tmp = CRC.calc_crc(ba, ba.Length);
                                tmpCs.setCrc(tmp.ToString("X"));
                            }

                            if (tmpCs.canSendByTimeout())
                            {
                                string crcStr = "?" + tmpCs.getCrc() + "?";
                                byte[] bb = Encoding.UTF8.GetBytes(crcStr);
                                crcStr = Encoding.UTF8.GetString(bb);
                                byte[] fullMsg = new byte[ba.Length + bb.Length];
                                bb[0] = 254;
                                bb[bb.Length - 1] = 255;

                                ba.CopyTo(fullMsg, 0);
                                bb.CopyTo(fullMsg, ba.Length);
                                string s = System.Text.UTF8Encoding.ASCII.GetString(fullMsg);

                                ns.Write(fullMsg, 0, fullMsg.Length);
                                Thread.Sleep(200);
                                if (!tmpCs.isAckNeeded())
                                    parent.cStructHandler.removeNextMsg(this.ID);
                            }
                        }
                    }
                    Thread.Sleep(100);
                }
                catch (Exception e)
                {
                    break;
                }

            }
            ns.Close();
            server.Close();
            dead = true;
        }
        catch (Exception e)
        {
            dead = true;
        }
    }



public void handleToDo()
    {
        try
        {
            int cnt = 0;
            while (true)
            {
                if (todo.Count > 0)
                {
                     //SWITCH CASE FOR DIFFERENT MESSAGE TYPES, DOING TASKS DEPENDING ON WHAT ONES...
                     Thread.Sleep(100);
                } 
                else
                {
                    if (dead)
                    {
                        todoT.Abort();
                        todoT = null;
                        break;
                    }
                }
                Thread.Sleep(200);
           }
      }
}

不明な点は質問してください。

/ニック

4

3 に答える 3

2

OSにはスケジューラがあります。各スレッドに等しい時間を与えようとすることはすでに機能しており、スレッドがいつ何かを待っているかについてより良い考えを持っています(したがって、与えられた時間を無駄にするだけです)。

あなたのより深い問題が何であるかはわかりませんが、これが解決策ではないと確信しています。有用な実際のコードのケースはほとんどありませSleep()(本番ではなく、調査およびテストコードに役立つケースが他にもいくつかあるため、「実際のコード」と言います)。とにかく、それらの非常に少数のケースのほとんどは、ライブラリコードですでに存在しています。それらのいずれも、より大きい値で呼び出す必要はなく、 。10より大きい値で呼び出す必要はありません0

これはそのようなケースの1つではありません。

于 2012-08-31T09:33:06.727 に答える
2

タスク プロデューサーが新しいタスクを格納し、タスク コンシューマーがタスクを取得して処理するための集中化された場所が必要です。コンシューマが作業を開始する前にすべてのタスクが生成される場合、問題は少し単純になります。作業スレッドはタスク コンシューマです。タスクは通常、タスクを完了するために必要なすべての関連データを含む 1 つのオブジェクトで表されます。どのスレッドがより高速で、どれだけのタスクを完了するかは重要ではないため、作業スレッドにはスリープの形式はありません。消費されるタスクがある限り、スレッドはループ内でタスクを消費します。この消費は、いくつかのロックによって保護されています。

編集:コードの再構築を提案して、すべての読み取りを非同期で行うスレッドが 1 つだけになるようにします ( BeginReadまたはReadAsync )。コードは各ソケットで読み取りを開始し、一部のソケットがデータを受信するか閉じるまで待機します。ソケットのデータが受信され、データが完了した場合次に、新しいタスクを作成します。不完全なデータをバッファリングし、データが完全になるまでさらに読み取る必要があります。タスクが生成されると、1 つのタスク コンシューマが最終的にタスクを取得して処理し、結果を対応するソケットに送信する必要があります。したがって、ソケットは 1 つのスレッドで読み取られ、複数のスレッドで書き込まれます。一部の競合状態を回避するために、メイン リーダー スレッドは、特定のソケットに対して生成された未完了の未完了のタスクがある場合、それ以上のデータを読み取ってはなりません。タスクが完了すると、メイン スレッドはさらにデータの読み取りを開始する場合があります。

テキストの壁ができてしまうので、すべてのコーナーをカバーしていません。すべての通信を行うライブラリがあるかもしれませんが、私は知りません。

于 2012-08-31T09:23:49.873 に答える
1

このような Sleep や while ループは使用しないでください。while ループを使用しても、あなたのケースでは Sleep は使用できません。

あなたの要件を本当に知らなくても、タイマーを調べることをお勧めします。

于 2012-08-31T09:10:39.953 に答える