C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[7]: ThreadPoolに溜まっている各スレッド全体の完了


(過去ログ 49 を表示中)

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■26896 / inTopicNo.1)  ThreadPoolに溜まっている各スレッド全体の完了
  
□投稿者/ 正規表現 (1回)-(2008/10/22(Wed) 16:47:07)

分類:[C#] 

「ThreadPoolに溜まっている各スレッド全体の完了待ち」の方法を教えて下さい。
/*
 * 環境 VS2008 FW3.5
 */
using System;
using System.Threading;

public class TaskInfo {
    public string sBoilerplate;
    public int iValue;

    public TaskInfo( string sText_ , int oNumber_ ) {
        sBoilerplate = sText_;
        iValue = oNumber_;
    }
}

public class Example {
    public static void Main() {
        const int iNumbOfTask = 100000;
        TaskInfo[] oTasks = new TaskInfo[iNumbOfTask];
        WaitCallback[] oWCall = new WaitCallback[iNumbOfTask];
        int iWorkerThreads;
        int iPortThreads;

        for ( int i= 0 ; i < oTasks.Length ; i++ ) {
            oTasks[i] = new TaskInfo("data = " , i);
            oWCall[i] = new WaitCallback(ThreadProc);
        }
        ThreadPool.GetMaxThreads(out iWorkerThreads , out iPortThreads);
        Console.WriteLine("A : " + iWorkerThreads.ToString() + " : " + iPortThreads.ToString());
        ThreadPool.SetMaxThreads(4 , 4);
        ThreadPool.GetMaxThreads(out iWorkerThreads , out iPortThreads);
        Console.WriteLine("B : " + iWorkerThreads.ToString() + " : " + iPortThreads.ToString());
        for ( int i= 0 ; i < oTasks.Length ; i++ ) {
            for ( ; ; ) {
                try {
                    ThreadPool.QueueUserWorkItem(oWCall[i] , oTasks[i]);
                    break;
                } catch ( Exception e ) {
                    Thread.Sleep(1000);
                }
            }
        }
        /*
        ThreadPool に 溜まっている 各スレッドの全体の完了待ち
        の方法が書かれているサイトを教えて下さい。
         */
        Thread.Sleep(10000);
        ThreadPool.GetMaxThreads(out iWorkerThreads , out iPortThreads);
        Console.WriteLine("C : " + iWorkerThreads.ToString() + " : " + iPortThreads.ToString());
        Console.WriteLine("Main thread exits.");
    }

    static void ThreadProc( Object oStateInfo_ ) {
        Thread.Sleep(1000); 
        TaskInfo oTInfo = (TaskInfo)oStateInfo_;
        Console.WriteLine(oTInfo.sBoilerplate + oTInfo.iValue.ToString());
    }
}

引用返信 編集キー/
■26966 / inTopicNo.2)  Re[1]: ThreadPoolに溜まっている各スレッド全体の完了
□投稿者/ 倉田 有大 (302回)-(2008/10/24(Fri) 01:57:14)
No26896 (正規表現 さん) に返信
> 「ThreadPoolに溜まっている各スレッド全体の完了待ち」の方法を教えて下さい。
> /*
> * 環境 VS2008 FW3.5
> */
> using System;
> using System.Threading;
>
> public class TaskInfo {
> public string sBoilerplate;
> public int iValue;
>
> public TaskInfo( string sText_ , int oNumber_ ) {
> sBoilerplate = sText_;
> iValue = oNumber_;
> }
> }
>
> public class Example {
> public static void Main() {
> const int iNumbOfTask = 100000;
> TaskInfo[] oTasks = new TaskInfo[iNumbOfTask];
> WaitCallback[] oWCall = new WaitCallback[iNumbOfTask];
> int iWorkerThreads;
> int iPortThreads;
>
> for ( int i= 0 ; i < oTasks.Length ; i++ ) {
> oTasks[i] = new TaskInfo("data = " , i);
> oWCall[i] = new WaitCallback(ThreadProc);
> }
> ThreadPool.GetMaxThreads(out iWorkerThreads , out iPortThreads);
> Console.WriteLine("A : " + iWorkerThreads.ToString() + " : " + iPortThreads.ToString());
> ThreadPool.SetMaxThreads(4 , 4);
> ThreadPool.GetMaxThreads(out iWorkerThreads , out iPortThreads);
> Console.WriteLine("B : " + iWorkerThreads.ToString() + " : " + iPortThreads.ToString());
> for ( int i= 0 ; i < oTasks.Length ; i++ ) {
> for ( ; ; ) {
> try {
> ThreadPool.QueueUserWorkItem(oWCall[i] , oTasks[i]);
> break;
> } catch ( Exception e ) {
> Thread.Sleep(1000);
> }
> }
> }
> /*
> ThreadPool に 溜まっている 各スレッドの全体の完了待ち
> の方法が書かれているサイトを教えて下さい。
> */
> Thread.Sleep(10000);
> ThreadPool.GetMaxThreads(out iWorkerThreads , out iPortThreads);
> Console.WriteLine("C : " + iWorkerThreads.ToString() + " : " + iPortThreads.ToString());
> Console.WriteLine("Main thread exits.");
> }
>
> static void ThreadProc( Object oStateInfo_ ) {
> Thread.Sleep(1000);
> TaskInfo oTInfo = (TaskInfo)oStateInfo_;
> Console.WriteLine(oTInfo.sBoilerplate + oTInfo.iValue.ToString());
> }
> }

スレッドが終了するたびにイベント送って確認かな。
なんか他に方法もありそうですが。
引用返信 編集キー/
■27170 / inTopicNo.3)  Re[2]: ThreadPoolに溜まっている各スレッド全体の完了
□投稿者/ 片桐 (116回)-(2008/10/29(Wed) 21:49:25)
片桐 さんの Web サイト
私がVB.NETで実現させた方法がありますよ。

クラスのStatic変数として2つ準備

A:実行JOB数をカウントするLong型
B:実行済JOB数をカウントするLong型

呼び出し元でThreadPoolへQueueするタイミングに、Aをインクリメント

ThreadPoolから呼び出されるスレッドの終了時に、Bをインクリメント

呼び出し元はA<=BとなるまでSleepで待機、

思いっきりベタなんですが、この流れで実現できています。
通常インクリメントにはInterLockedを使えばよいのですが、64BitOS上の複数CPUで動作させる場合、うまくスレッド同期が働きません。実際4個ではうまくいきましたが16個では失敗しました。ですので、SyncLockによるスレッド同期で動かすことが望ましいかと思います。


引用返信 編集キー/
■27173 / inTopicNo.4)  Re[3]: ThreadPoolに溜まっている各スレッド全体の完了
□投稿者/ なちゃ (195回)-(2008/10/29(Wed) 22:10:35)
一般にはCountDownLatchなんてのが使われます。
が、.NETには現時点では入ってませんので、使いたいなら自作する必要があります。

一応参考
http://msdn.microsoft.com/ja-jp/magazine/cc163427.aspx

まあ、片桐さんが書かれているようにべたで処理してもいいですけどね。

ところで、
No27170 (片桐 さん) に返信
> A:実行JOB数をカウントするLong型
> B:実行済JOB数をカウントするLong型
>
> 呼び出し元でThreadPoolへQueueするタイミングに、Aをインクリメント
>
> ThreadPoolから呼び出されるスレッドの終了時に、Bをインクリメント
>
> 呼び出し元はA<=BとなるまでSleepで待機、

まあ変数はAだけで、投入時にカウントアップ、終了時にカウントダウンでいいと思います。
あるいは投入数が事前に決まってるならその値で初期化して、終了時にカウントダウンのみ。
カウントダウンラッチなんかはこういうやり方です。

それと、待機はManualResetEventや、Monitorを使うほうがいいです。
カウントの変数はIntegerで十分ですね。

※Interlockedを使う場合、32ビット環境だと、64ビットのインタロック操作が正常に動作する保証がない
 (64ビット変数が64ビット境界に配置される保証がない)というのを読んだ記憶があります。

> 通常インクリメントにはInterLockedを使えばよいのですが、64BitOS上の複数CPUで動作させる場合、うまくスレッド同期が働きません。実際4個ではうまくいきましたが16個では失敗しました。ですので、SyncLockによるスレッド同期で動かすことが望ましいかと思います。

これって32ビットの場合の話じゃなくて、64ビットCPUで駄目って話ですか?
私が見たことあるのは、上記のように32ビットCPUで64ビットを使うと駄目かもしれない、という話です。

64ビットCPUで正しく動作しないとは考えにくいのですが、本当にうまく動かないんでしょうか?
どういうふうに失敗したんでしょうか?プログラム(使い方)の間違いということはないですか?

引用返信 編集キー/
■27175 / inTopicNo.5)  Re[4]: ThreadPoolに溜まっている各スレッド全体の完了
□投稿者/ なちゃ (196回)-(2008/10/29(Wed) 22:12:53)
No27173 (なちゃ さん) に返信
> ※Interlockedを使う場合、32ビット環境だと、64ビットのインタロック操作が正常に動作する保証がない
>  (64ビット変数が64ビット境界に配置される保証がない)というのを読んだ記憶があります。

これですが、64ビットのReadメソッドがうまく動作しないという限定的な話だったかもしれません(思い出せず)。

引用返信 編集キー/
■27178 / inTopicNo.6)  Re[5]: ThreadPoolに溜まっている各スレッド全体の完了
□投稿者/ なちゃ (197回)-(2008/10/29(Wed) 22:57:59)
Monitor使ったごく簡単なカウントダウンラッチも書いてみた。
特に工夫なしバージョン。
※カウントダウンラッチとか使う場合、スレッド(タスク)終了時に
 確実にCountDownをしないと永久に停止するので注意

使い方
SimpleCountDownLatchをタスク数で初期化して、各タスクは終了時にCountDownを呼ぶ(finallyで確実に呼ぶこと)。
完了待ち側は単にWaitを呼ぶ。

http://msdn.microsoft.com/ja-jp/magazine/cc163427.aspx
のを使う場合でも同じ(メソッド名とかちょっと違うけど)。


using System;
using System.Threading;

public class SimpleCountDownLatch
{
private readonly object m_lock = new object();
private int m_count;

public SimpleCountDownLatch(int count)
{
m_count = count;
}

public void Wait()
{
if (m_count <= 0) return;
lock (m_lock)
{
// .NET ではスプリアスウェイクアップって起こりうるのか良く分からないので
// 念のため while で処理(ifで十分かもしれない)
while (m_count > 0) Monitor.Wait(m_lock);
}
}

public void CountDown()
{
if (m_count <= 0) return;
lock (m_lock)
{
// 若干非同期例外が気にならくもないけど無視
if (--m_count == 0) Monitor.PulseAll(m_lock);
}
}
}
引用返信 編集キー/
■27182 / inTopicNo.7)  Re[6]: ThreadPoolに溜まっている各スレッド全体の完了
□投稿者/ れい (819回)-(2008/10/30(Thu) 03:21:37)
No27170 (片桐 さん) に返信
> 私がVB.NETで実現させた方法がありますよ。

No27178 (なちゃ さん) に返信
> Monitor使ったごく簡単なカウントダウンラッチも書いてみた。

それって、「ThreadPoolに明示的に溜めたタスク全体の完了待ち」ですよね。

No26896 (正規表現 さん) に返信
> 「ThreadPoolに溜まっている各スレッド全体の完了待ち」の方法を教えて下さい。

とあるので、もしかするとちょっと違うのではないかと。

ThreadPoolのThreadはいろいろなことに使われているので、
明示的にプールに入れるタスクとは対応しません。

そのくらい空気よめ、ってことだったり、言葉のあやなのかもしれませんが…。

#厳密に日本語を読むなら、
#スレッドプールのスレッドはアプリケーション終了まで完了しないで待機してるので、
#各スレッドは完了待ちはできない、ってことになってしまいますね

ThreadPoolが暇をもてあますまで待ちたい、というなら、こんなのはどうでしょう?

Dim max_worker As Integer
Dim max_port As Integer
Dim avail_worker As Integer
Dim avail_port As Integer
Do
ThreadPool.GetMaxThreads(max_worker, max_port)
ThreadPool.GetAvailableThread(avail_worker, avail_port)
Loop While max_worker > avail_worker OrElse max_port > avail_port

ダメ、ですよね…。

引用返信 編集キー/
■27183 / inTopicNo.8)  Re[7]: ThreadPoolに溜まっている各スレッド全体の完了
□投稿者/ なちゃ (198回)-(2008/10/30(Thu) 03:28:31)
No27182 (れい さん) に返信
> それって、「ThreadPoolに明示的に溜めたタスク全体の完了待ち」ですよね。
>
> ■No26896 (正規表現 さん) に返信
>>「ThreadPoolに溜まっている各スレッド全体の完了待ち」の方法を教えて下さい。
>
> とあるので、もしかするとちょっと違うのではないかと。

ま、それは思ったんですが、なんとなく最初のコード見たらまあやりたいのはこんなとこでいいんだろうと。

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -