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

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

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

Re[5]: メソッドの作り方


(過去ログ 79 を表示中)

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

■46814 / inTopicNo.1)  メソッドの作り方
  
□投稿者/ OROCHI (2回)-(2010/02/11(Thu) 16:40:59)

分類:[C#] 

OS:Windows XP
開発;Visual Studio 2005

こんにちは
現在「複数のファイルを読み込む」→「読み込んだ内容を表示する」というプログラムを作っています
が、ファイルの対象がそれぞれ大きいので、普通に順に読み込んでいくとロード時間が長くなってしまいます
そこで、「マルチスレッドを利用して同時に読む」という方法を考えているのですが、途中でソースの書き方が解らなくなっています

途中まで作ったソースは以下の通りです(質問に関係のないところは一部省略しています。よくわからない変数名や関数名はこちら独自のものと考えてください)

class Program
    {
        static readonly object syncObject = new object();   // 同期オブジェクト

        static int load_num = 2;

    public int num;

        // ロードした内容を保存する構造体の配列です。
        private Character[] npcCHA = new Character[load_num];
    
        static void Main(string[] args)
        {
            // スレッド作成
            Thread []sload = new Thread[load_num]; 

            num = 0;
            
            // スレッド実行開始
                         
            // ここが問題
            

            Console.WriteLine("Load Complete");
            Console.ReadKey();
        }

    // ファイルを読む関数です
        public void SecondLoad()
        {
            lock (syncObject)
            {
                // ここにファイルを読むための処理
                npcCHA[0].LoadC3DFile(cyber3D.device, "..\\..\\..\\..\\Character\\nayuki\\", "nayuki_normal.c3d");
                Thread.Sleep(1);
                
            }
        }
    // npcCHA[1]に書き込む関数もここにいる?

    }

ここで問題になるのが肝心要のスレッドを作る部分を書く方法が解らず困っています
当初は以下のように書いたのですが

sload[0] = new Thread(new ThreadStart(SecondLoad));

エラー	1	
静的でないフィールド、メソッド、またはプロパティ 'High_Speed_load_test.Program.SecondLoad()' で、オブジェクト参照が必要です。

と出てしまいます。かといってSecondLoadをstaticにしてしまうと
npcCHAの操作ができなくなり、ファイルを読むという本来の目的が達成できません
別のクラスにSecondLoadをおいても同じ問題が発生します

というのも読み込んだファイルの内容はnpcCHAという構造体配列の中に入り、
後でMainの中でnpcCHAの内容を表示する形になるからです
(厳密にはちょっと違うのですが、class Programの中のどこからでもアクセスできる必要があります)。

あと、これはついでなのですがメソッドに引数を与える方法というのはあるものなのでしょうか?
というのは、各スレッドで読むファイルの内容は全部異なるので、今の方法だと読み込むファイル分メソッドを用意しなくてはならなくなります



引用返信 編集キー/
■46820 / inTopicNo.2)  Re[1]: メソッドの作り方
□投稿者/ Azulean (516回)-(2010/02/11(Thu) 18:08:58)
No46814 (OROCHI さん) に返信
> と出てしまいます。かといってSecondLoadをstaticにしてしまうと
> npcCHAの操作ができなくなり、ファイルを読むという本来の目的が達成できません
> 別のクラスにSecondLoadをおいても同じ問題が発生します

static にする路線なら、static メソッドから呼び出されるメソッドを static にし、メソッドからアクセスするフィールドを static にしていけば、いずれは解消します。
(極論を言えば、Program クラスにあるすべてのメンバーを static にすれば良い)

逆に、インスタンスメソッドであることを維持したいのであれば、下記のように呼び出せば良いでしょう。

Program p = new Program();
Thread t = new Thread(new ThreadStart(p.SecondLoad));

インスタンスがどういったものであるか、static をつけたものがどういったものであるかについて、復習してください。

> あと、これはついでなのですがメソッドに引数を与える方法というのはあるものなのでしょうか?
> というのは、各スレッドで読むファイルの内容は全部異なるので、今の方法だと読み込むファイル分メソッドを用意しなくてはならなくなります
メソッドに引数を渡すことはできますが、なぜご質問されたのでしょうか?
書き方が全く分からないのであれば、基礎を体系的に学べる書籍などを購入して勉強してください。
引用返信 編集キー/
■46822 / inTopicNo.3)  Re[2]: メソッドの作り方
□投稿者/ OROCHI (4回)-(2010/02/11(Thu) 18:32:55)
> Program p = new Program();
> Thread t = new Thread(new ThreadStart(p.SecondLoad));

ありがとうございました。この方法で解決できました

> メソッドに引数を渡すことはできますが、なぜご質問されたのでしょうか?
> 書き方が全く分からないのであれば、基礎を体系的に学べる書籍などを購入して勉強してください。

書き方が悪くて申し訳ありません
当初、SecondLoadに引数を渡せるようにしようとして以下のように書いていました

public void SecondLoad(int a)
{
  // 中身は省略
}

が、このメソッドを呼び出す部分で以下のように書くと
sload[a] = new Thread(new ThreadStart(p.SecondLoad(a)));

「メソッド名が必要です」というエラーが出ます

ということで「Threadで呼び出すメソッドに」引数を与える方法という意味です
混乱させて申し訳ありませんでした。

引用返信 編集キー/
■46823 / inTopicNo.4)  Re[3]: メソッドの作り方
□投稿者/ Azulean (518回)-(2010/02/11(Thu) 18:48:15)
No46822 (OROCHI さん) に返信
> sload[a] = new Thread(new ThreadStart(p.SecondLoad(a)));
>
> 「メソッド名が必要です」というエラーが出ます

Thread クラスのコンストラクタを見ればヒントを得られませんか?
http://msdn.microsoft.com/ja-jp/library/system.threading.thread.thread.aspx

複数個渡したいのであれば、クラスを作ってそのインスタンスを渡すようにすれば良いでしょう。
引用返信 編集キー/
■46828 / inTopicNo.5)  Re[4]: メソッドの作り方
□投稿者/ OROCHI (5回)-(2010/02/11(Thu) 20:56:13)
> 
> Thread クラスのコンストラクタを見ればヒントを得られませんか?
> http://msdn.microsoft.com/ja-jp/library/system.threading.thread.thread.aspx
> 
以下のソースでなんとかなりました。ありがとうございます

// 構築部はこんな感じ
sload[a] = new Thread(p.SecondLoad);
sload[a].Start(a);

// メソッドはこんな感じです。objectは暗黙変換不可なのですね
public void SecondLoad(object data)
        {
            lock (syncObject)
            {
                Console.WriteLine("nowdata:" + data);
                switch (((IConvertible)data).ToInt32(null))
                {
                    case 0:
                        //npcCHA[0].LoadC3DFile(cyber3D.device, "Character\\nayuki\\", "nayuki_normal.c3d");
                        break;
                    case 1:
                        //npcCHA[1].LoadC3DFile(cyber3D.device, "Character\\nayuki\\", "nayuki_normal.c3d");
                        break;
                };
                Thread.Sleep(1);
                
            }
        }

解決済み
引用返信 編集キー/
■46829 / inTopicNo.6)  Re[5]: メソッドの作り方
□投稿者/ Azulean (520回)-(2010/02/11(Thu) 21:16:16)
No46828 (OROCHI さん) に返信
> switch (((IConvertible)data).ToInt32(null))
int であることが分かっているのであれば、下記のようにすれば良いでしょう。

switch ((int)data)

引用返信 編集キー/
■46919 / inTopicNo.7)  Re[5]: メソッドの作り方
□投稿者/ Jitta (634回)-(2010/02/14(Sun) 14:54:59)
Jitta さんの Web サイト
No46828 (OROCHI さん) に返信
 マルチスレッドでなくても、非同期読み込みという方法も、あったり。

class CharactorMap
{
  public string FilePath {
    get;
    set;
  }
  public string FileName {
    get;
    set;
  }
  public CharactorMap(string p, string n) :
    FilePath(p), FileName(n) {
    // ↑この書き方出来るんだっけ?
  }
}
CharactorMap[] chars = {
  { @"Character\nayuki", "nayuki_normal.c3d"},
  { @"Character\nayuki", "nayuki_normal.c3d"}
};
public void SecondLoad(object data)
{
  // 0 や 1 って書いたら、増えたときの対応が難しい
  // lock したら、シングル スレッドと変わらない
  int a = (int) data;
  npcCHA[a].LoadC3DFile(cyber3D.device, chars[a]);
  // なんのための Sleep(1) です?
}

解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -