プロが教えるわが家の防犯対策術!

現在、C++を利用してマルチスレッド環境の開発を行っています。

マルチスレッドで排他的に変数を扱う場合、クリティカルセクションや

ミューテックスを使用することで、排他制御をおこなうことができますが、

このように、配列の要素ごとに排他制御を行うことは可能でしょうか?

たとえば、

int ary[10];

のような配列があれば、a[0]~a[9]まで要素をそれぞれ排他制御によって

データの矛盾を避けたいと考えています。

パフォーマンスの関係上、できるだけ、配列全体をロックするのは避けたいと

思っています。

どうぞよろしくお願いします。

A 回答 (3件)

 こんばんは。

windowsで良ければ、

 「InterlockedExchange()API」
 http://msdn.microsoft.com/ja-jp/library/cc429230 …

 を使用するか、配列の個数分クリティカルセクションリソースを用意して、各要素に応じたクリティカルセクションリソースをロックすれば出来ると思います。
 アラもあるとは思いますので、以下参考程度に(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;
}
    • good
    • 0

マルチスレッド環境での効率的な短時間の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_s …
"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) {
...
}
    • good
    • 0

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

    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!