• ベストアンサー

マルチスレッド環境での配列使用について

現在、C++を利用してマルチスレッド環境の開発を行っています。 マルチスレッドで排他的に変数を扱う場合、クリティカルセクションや ミューテックスを使用することで、排他制御をおこなうことができますが、 このように、配列の要素ごとに排他制御を行うことは可能でしょうか? たとえば、 int ary[10]; のような配列があれば、a[0]~a[9]まで要素をそれぞれ排他制御によって データの矛盾を避けたいと考えています。 パフォーマンスの関係上、できるだけ、配列全体をロックするのは避けたいと 思っています。 どうぞよろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • ninoue
  • ベストアンサー率52% (1288/2437)
回答No.2

マルチスレッド環境での効率的な短時間のin-memory排他的処理は、 次のような形で実現可能です。 H/W命令として cswap: compare and swap 或いは相当の命令がpowerpc,intel他最近の machineでサポートされているので、それを有効活用します。 http://ja.wikipedia.org/wiki/コンペア・アンド・スワップ H/W 命令については 例えば "instruction manual cmpxchg intel"でサーチ下さい。 Intel(R) Architecture Software Developer's Manual, Volume 2: Instruction Set Reference Manual lock-cmpxchg サブルーチン実装例については google code search でサーチ下さい。 http://www.google.com/codesearch/advanced_code_search "compare and swap" lang:c++ etc. "cmpxchg" lang:assembly etc. 概略の動作は次のような形で実現します。 C++は使っていないので次は擬似コーディングとして参照下さい。 data-blockに関してのlockが必要な場合、int ary[i]相当のlockwordを data-blockとは別に設けて、そのlockwordにより排他制御を実現します。 data update: loop: xold = ary[i]; // generate new data xnew = xold +delta; // xprev = cswapsub(&ary[i],xold,xnew); if (xprev!=xold) { // call delay_sub to suppress excessive cswap contention; // about 500-inst. or 0.5microsec // (about 10*lock-cmpxchg inst.time ?) // try to avoid memory store in loop as much as possible goto loop; } ... data reference: loop:  xold = ary[i]; ... data handling // reference xprev = cswapsub(&ary[i],xold,xold); // check ary[i] data same while processing if (xprev!=xold) { // call delay_sub to suppress excessive cswap contention; // about 500-inst. or 0.5microsec // try to avoid memory store in loop as much as possible } int cswapsub(int* &data, olddata, newdata) { ... }

その他の回答 (2)

回答No.3

 こんばんは。windowsで良ければ、  「InterlockedExchange()API」  http://msdn.microsoft.com/ja-jp/library/cc429230.aspx  を使用するか、配列の個数分クリティカルセクションリソースを用意して、各要素に応じたクリティカルセクションリソースをロックすれば出来ると思います。  アラもあるとは思いますので、以下参考程度に(InterlockedExchangeの方です)。 // consoe.cpp : コンソール アプリケーションのエントリ ポイントを定義します。 // #include "stdafx.h" #define NOMINMAX #include <windows.h> #include <process.h> #include <iostream> #include <algorithm> #include <cmath> static const int NUMARR = 10; static const int NUMTHREAD = 2; unsigned WINAPI ThreadA(void* p) { LPLONG a = static_cast<LPLONG>(p); for(int i = 0; i < 12000; ++i) { for(int n = 0; n < NUMARR; n += 2) { const LONG v = ::InterlockedExchange(&a[n], 0); ::InterlockedExchange(&a[n], v + (std::rand() % 100)); } ::Sleep(0); } return 0; } unsigned WINAPI ThreadB(void* p) { LPLONG a = static_cast<LPLONG>(p); for(int i = 0; i < 25000; ++i) { for(int n = 1; n < NUMARR; n += 2) { const LONG v = ::InterlockedExchange(&a[n - 1], 0); ::InterlockedExchange(&a[n - 1], v); ::InterlockedExchange(&a[n], v / std::max(std::rand() % 100, 1)); } ::Sleep(0); } return 0; } int _tmain(int argc, _TCHAR* argv[]) { LONG a[NUMARR] = {0,0,0,0,0,0,0,0,0,0}; HANDLE threads[NUMTHREAD] = { reinterpret_cast<HANDLE>(::_beginthreadex(NULL, 0, &::ThreadA, a, 0, NULL)), reinterpret_cast<HANDLE>(::_beginthreadex(NULL, 0, &::ThreadB, a, 0, NULL)), }; ::WaitForMultipleObjects(NUMTHREAD, threads, TRUE, INFINITE); for(int i = 0; i < NUMTHREAD; ++i) ::CloseHandle(threads[i]); for(int i = 0; i < NUMARR; ++i) std::cout << "a[" << i << "] = " << a[i] << std::endl; return 0; }

回答No.1

できますよ、配列に見せかけたクラスを作ればいい。

関連するQ&A

  • マルチスレッドについて。

    今、大きな配列を元に処理を行うプログラムを作成しています。 シングルスレッドでも十分速度を向上するようチューニングに成功しましたが、マルチスレッド化をすればさらに速度を向上させることができるだろうと考え、先日マルチスレッドかに成功しました。 しかし・・・奇妙な現象が起こりました。 マルチスレッドで性能を引き出すには、排他制御はないほうが良いと考え、メモリは食いますがスレッドに与える入力情報(大きな配列)を2つ用意し、排他制御なしの2スレッドを実行できるようにしました。しかしやはりメモリを消費しすぎてしまうため、配列にアクセスする部分のみ排他制御を行うようクリティカルセクションを設定し入力情報を2スレッドで共有して処理を行うよう組み替えました。 結果、やはり排他制御なしの場合よりはるかにスピードダウンしてしまい、シングルスレッドより少し早い処理時間で終了してしまいました。 余りにも悔しいため、ちょっと危険な実験だとは思いましたが、入力情報を2つのスレッドで共有しているにもかかわらず、排他制御の部分、つまりクリティカルセクションを取り除いて実行してみようと考えました。予想としては同時にアクセスし衝突が起きてエラーで停止してしまうと考えましたが・・・・・・ 結果なぜかエラーなく処理をし続け、普通に終了してしまいました。 これはなぜでしょう? 偶然にも共有情報に同時にアクセスすることがなかったためでしょうか?

  • マルチスレッドの疑問点と配列について

    こんばんわ。 VC++.NET2003を用いて、C言語プログラミングを行っています。以下に質問内容をまとめます。 1.現在、マルチスレッドを行っています。マルチスレッドの注意点として、 ・スレッドが複数同時に処理(現在2スレッド)され、それぞれのスレッドで同一のグローバル変数をアクセスする。 ・各スレッドで使用しているスタティック変数はプロセスとして1つの領域に確保される。 と記述されていました。 現在、2スレッド動かしているのですが、2スレッド共通で使用したい変数がある場合は、グローバル変数として宣言してよいのでしょうか? スタティック変数というのは、 static int i を指すのでしょうか・・・・初心者的発言で申し訳ありません。 次にもう一つ質問させていただきます。 配列を整数型で10000要素、静的に用意します。 これを、memset関数ですべての番地に0を初期値として入れておきます。 たとえば、9000という数字があった場合、9000番に整数値9000を格納する。また、56では56番に56を格納する。 そして、最終的に10000要素を走査し0の場所をカウントする。 ということは可能でしょうか?もしよろしければ、サンプルを教えていただきたいと思っています。 よろしくお願い致します。

  • マルチスレッド化。

    今とても大きな配列を使用し、長時間処理をするプログラムを組んでいます。元々処理時間に1時間を要するプログラムを2分で処理を完了するまでに仕上げました。 しかし、探究心はおさまらずもう少し高速化に挑みたいと考えています。 過去に「猫でもわかる」のSDK第1章と2章を学び、マルチスレッドのプログラムをSDKで組んだことがあります。それを利用してマルチスレッド化を実現したいと考えています。 言語はCでVisualStudio2005を使用しています。 *疑問1   SDKの場合WinMain関数とプロシージャからの実行で_beginthread関数を記述すれば処理が開始されます。 Cでもmain関数内に記述すれば、SDKと同様に処理できるのでしょうか? *疑問2 _beginthread関数の引数に関してです。 第1引数にvoid型のスレッド関数、第2引数に0?、そして第3引数にはスレッド関数に渡すデータの引数を記述すると把握しているのですが、渡したいデータは複数あり、***型と**型、それに変数を数個とスレッド関数に渡したいデータだらけなのですが、どのように記述すればよいでしょう? *疑問3 2つのスレッドを作成しようと考えていますが、その2つのスレッドで1つの大きな配列を共有して処理したいと考えています。 そのため、スレッド間の同期が必要になるわけですが同期の種類にもクリティカルセクションやミューテックス、イベントと豊富でどれを使用すれば良いのか迷ってしまいます。厳密に同期を取り処理をするにはイベントが一番良いと考えています。 これらの疑問に答えられる方はアドバイスをよろしくお願いします。

  • (マルチスレッド)_beginthreadexに複数の引数を渡す

    現在プログラムでマルチスレッドをやろうとしているのですが、 マルチスレッドの関数に数値や配列などの引数を渡すことは可能でしょうか? MSDNで調べてみると、_beginthreadex関数の4番目のNULLのところに引数リストを 指定できるとあったのですが、その意味が良くわかりませんでした。 以下のプログラムの場合にマルチスレッドに変数a, b, cを引数として渡したい場合は どのように書けばいいのでしょうか? #include <stdio.h> #include <windows.h> #include <process.h> unsigned WINAPI MyThread( void *lpx ){ while (1) { printf("スレッド実行中\n"); Sleep(1000); } return 0; } void main(){ // スレッドに渡したい変数の宣言 int a = 128; int b = 256; int c = 512; // スレッドIDの宣言 DWORD thID; // マルチスレッドの開始 (HANDLE)_beginthreadex( NULL, 0, &MyThread, NULL, 0, (unsigned int*)&thID ); // ループ while (1) { printf("メイン関数実行中\n"); Sleep(2000); } }

  • 引数が配列のときの関数内でのsizeofについて

    こんにちは. Cを勉強している最中に疑問にあったことを質問させていただきます.以下のプログラムで配列myarrayの中の最大のメンバーを見つけるプログラムです.コメントアウトしてある //int ary_size = sizeof(myarray)/4; をグローバル変数で定義するとうまく最大の数を見つけてくれるのですが, 関数の中で int ary_size = sizeof(ary)/4; と定義するとうまくいきません.そこで,以下の printf("The size of the ary is %d\n",ary_size); という表示を追加したところ,ary_size = 1となっていることが分かりました. なぜそうなるのでしょう?関数の引数はint ary[]の配列なので,sizeof(ary)でaryがメモリ中で占めるバイト数が得られるんじゃないんですかね?ちなみに私の環境ではsizeof(int)は4バイトなので int ary_size = sizeof(ary)/4; と割る4で配列のメンバーの数を求めています. 初心者の質問ですみませんがよろしくお願いします. #include <stdio.h> #include <Windows.h> int myarray[] = {1,2,3,4,5,6,7,2}; int FindMax(int ary[]); //int ary_size = sizeof(myarray)/4; int main() { int max; max = FindMax(myarray); printf("The maximum value is %d\n",max); Sleep(2000); return(0); } int FindMax(int ary[]) { int ary_size = sizeof(ary)/4; int i; int max; max = ary[0]; for(i=1;i<ary_size;i++) { if(ary[i]>max) { max = ary[i]; } } printf("The size of the ary is %d\n",ary_size); return(max); }

  • 引数で指定された配列の要素数の取得

    どうもこんにちは。 C言語でプログラムを作成しています。 ある関数に配列を渡すことを考えていますが、渡した配列の要素数を取得する方法は何かありますか? 標準の関数を見ても、配列の先頭アドレスのポインタとともに、配列の要素数を渡しているものばかりで、配列のポインタを渡しているものは見かけません。 要素数があらかじめわかっていれば、それを引数の型に指定できますが、呼び出されるまで不明な場合はうまくいきません。 配列の要素数も引数として一緒に渡す必要がありますか? [作ってみたサンプル] #include <stdio.h> #include <stdlib.h> #include <string.h> // func1 と func2 をまとめられないだろうか。。。 void func1(int (*p)[10]) { ________int n = sizeof(*p) / sizeof((*p)[0]); ________int i; ________for (i = 0; i < n; i++) { ________________printf("%d\n", (*p)[i]); ________} ________printf("\n"); } void func2(int (*p)[5]) { ________int n = sizeof(*p) / sizeof((*p)[0]); ________int i; ________for (i = 0; i < n; i++) { ________________printf("%d\n", (*p)[i]); ________} ________printf("\n"); } int main(int argc, char *argv[]) { ________int ary1[10] = { 2, 4, 6, 8, 0, 1, 3, 5, 7, 9 }; ________int ary2[5] = { 3, 6, 9, 12, 15 }; ________func1(&ary1); ________func2(&ary2); ________return 0; }

  • Javascriptの配列の便利な処理

    Javascriptの配列で以下のような処理は自分で作らないといけないのでしょうか? var csv = 'A,B,C,D'; var ary new Array(); ary = csv.split(','); 要素の有無 true/false ary.exists('A') 結果 true 要素の削除 ary.delete('A') 結果 ary = ['B', 'C', 'D'];

  • 配列の要素数に変数を入れたいときには

    よろしくお願いします。 配列の要素数には定数しか入れられないのですが,どうしても変数を入れたいときは,それを引数として関数を呼び出すしか方法はないでしょうか。 具体的には,scanfで手に入れたint型の変数を要素数とする配列を宣言したいのですが,どうすれば良いでしょうか。 ご教授ください。

  • 配列の定義について

    配列とは、同じ形式のデーターを連続した記憶領域で確保するためのものである。 配列を構成する個々の領域を要素と呼び、要素の位置を添え字で示す。 Javaでは配列の先頭の要素を(0)番目と呼ぶ。 今、hairetsuという名前で10個の整数からなる配列を定義したい。 この場合の配列は(0)番目から始まり、終端は(9)番目である。 これを定義するには (int[] hairetsu;) (hairetsu = new int[10];) のように2行で行う方法と、 (int[] hairetsu = (new int[10];) のように、一行で行う方法がある。 Javaでは定義済みの配列の要素数は、配列変数名.(length)で知ることができ、 終端は(length + 1)番目となる。 したがって(length + 1)番目以降を使おうとすると、 配列要素の範囲外で(例外)が発生する。 この文章の( )の中は間違っていますか?

    • ベストアンサー
    • Java
  • C♯の配列について

    C♯でプログラムを作っているのですが、配列の要素数の最大値と最小値の求め方がわかりません。配列の値の最大値の求め方は調べれば出てくるのですが、要素数の最大値等は調べてもわかりませんでした。 例えば下記のような配列があった場合 int[,,] a =new int[100,100,100] a[2,3,6]=1 a[4,5,9]=1 a[13,46,79]=1 a[8,15,45]=1 a[1,33,68]=1 それぞれの要素数の最小値1、3、6、最大値13、46、79は どのようにプログラムで求めればいいのでしょうか? よろしくお願いします。