質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

6238閲覧

マルチスレッドでの遅延処理について

TEC_S

総合スコア79

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1グッド

1クリップ

投稿2016/07/06 05:59

編集2016/07/06 13:05

###前提・実現したいこと
Visual Studio2010を使用して画像を取得するアプリケーションを作成しています。
1秒間に0.1GB程度(実質60MB/s)のデータをフレームレートが30程度のスピードにて取得してファイル出力(HDDへ)するのが目的のため、ファイル出力分の遅延処理が発生します。遅延時にも画像データを取りこぼさないよう、スレットを複数に分けて、処理を行おうと考えています。

###発生している問題
700枚程度までは、画像取得・保存・遅延時には、保存スレッド・遅延スレッドでの保存が出来ているが、それ以降300フレーム程の保存漏れが発生(全部で1800枚程度取得)。

700枚程度までは普通に動いているのに、一部、全く動かない事があり、困っています。
3つのスレッドを、どう管理したら良いのでしょうか。アドバイス頂ければ幸いです。

処理の内容として

☆画像取得スレッド(メインスレッド)
①画像情報を取得
②既存の画像取得用リストの上限を確認
③確認して上限を超えそうなら、上限を超えそうな数分、遅延用リストへ移す
④上限に達していなければ取得用リストへ入れる
①へ

☆保存処理スレッド
①画像取得スレッドの取得リストを確認、データが取得されていれば、リストからデータを取得
②画像保存
③保存したリストを削除
①へ

☆遅延処理スレッド
①空ループにて遅延用リストを監視
②遅延用リストにデータが入ってきたら、保存処理
③保存したらリストからデータを削除
①へ

###試したこと
画像取得スレッド・保存処理スレッドだけでは、遅延分の画像を保存できなかった為、遅延スレッドを作成。
遅延用のリスト構造を作成して監視し、非同期にて遅延分の画像を保存するようにした。

デバック用のLogを出力するようにしたところ、画像取得スレッドの、①~③のみが動いている時があり、肝心の保存処理・遅延スレッドでの保存が出来ていない事があった。(700枚程度の取得までは可能だが、そこらへんから一気に取得漏れが発生)。

KiyoshiMotoki👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

こんにちは。

画像取得スレッド・保存処理スレッドだけでは、遅延分の画像を保存できなかった為、遅延スレッドを作成。

画像取得スレッド・保存処理スレッドだけの時、なにがボトルネックだったでしょうか?
通常は、取得スレッドと保存スレッドの2つを用い、間にFIFOを挟むことで、保存処理の突発的な遅延に対処できる筈です。そして、書かれている内容だけならば、FIFO(取得リスト?)にて既に突発的な遅延には対処できる筈ですので、2重に遅延対策を入れる意味はないように思えます。

ありがちな問題は「平均のデータ発生速度 > 平均の保存速度」ですね。この場合、平均の保存速度がボトルネックですので、保存速度を上げるか、データ発生速度を落とすか、データを間引く等の対策が必要です。

CrystalDiskMarkでHDDの速度を計測しておくことをお勧めします。巨大なファイルの保存でしたら、512KBytes Random Writeが目安になるのではないか思います。
それを超える速度でデータが発生するようでしたらHDDを増やして分散書き込みする等の対策が必要と思います。
1GBytes/Secを超える保存性能を持つHDDはコンシューマ製品ではまだまだ存在しないような気がします。

また、フォルダ内のファイル数が数万個を超えてくると、8.3形式が悪さをしてびっくりする程速度が低下します。もし、画像を1枚1枚別ファイルとして保存している等で多量のファイルがあるようでしたら、8.3形式をDisableすると効果的です。

最初の700枚を取りこぼさないのはキャッシュが効いているためだと思います。

投稿2016/07/06 07:07

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TEC_S

2016/07/06 08:26

ご回答、ありがとうございます。 ご指摘の問題の通り、データの発生速度が保存速度を上回っているのがボトルネックになっていました。(保存処理をやらないと遅延が起きない為) また、自分の考え方が違っていました。保存処理にて遅延するのだから、保存処理を違うスレッドにてやれば、負荷が分散するかと考え、対処しようとしていました。それだと結局、破綻してしまうのですね・・・。 アドバイスありがとうございます。早速CrystalDiskMarkで測定を行います。 データ発生速度を落とす事は出来ない(仕様上)為、保存速度を上げるか、、分散書き込みか、まとめて保存(これを先ず試してみます)をするようにして、ボトルネックを改善しようと思います。
Chironian

2016/07/06 09:11

> まとめて保存(これを先ず試してみます)をするようにして、ボトルネックを改善しようと思います。 最大の保存速度の理論値はシーケンシャル書き込み速度です。それが1GBytes/Secを下回っている場合は理論上できません。 また、もし、シーケンシャル書き込み速度が1GBytes/Secを超えていたとしても、ファイルシステムがその性能を出せないと無理です。HDDでは厳しいです。SSDならシーク時間がないのでもしかすると可能性はあるかも。 ↓は1GBytes/Secを超える性能を出しているそうです。 http://weekly.ascii.jp/elem/000/000/321/321921/ コンシューマ向けハイエンドSSDだそうです。結構高そうですが1GBytes/Secという超高速で保存したいようなビジネスなら費用を賄えるかも? しかし、本当に1GBytes/Secなのですね。 通常HDD I/FはシリアルATAです。最新の3.0でも実効転送速度は600MBytes/Secだそうです。シリアルATAに接続するHDD 1台では1GBytes/Secで保存するこは事実上不可能です。 https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%ABATA 上記のSSDはPCIe 3.0×4を使うそうです。1GBytes/Secというと、ストレージにはあまり使わないI/Fを使う必要がある速度なのです。 念のため、1GBits/Secではないのですよね? 1GBits/Secなら1/8の転送レートで良いのでシリアルATA接続のHDDでも対応できるものがあるかも知れません。(まだまだレアな気もしますが)
TEC_S

2016/07/06 12:57

大変申し訳ありません。私の勘違いで桁が一つ違い、、0.1Gbyte/Secでした。 しかも、ざっくり書きすぎました。1フレーム2MBで、実際には60MB/Secです。 CrystalDiskMarkにてHDDの書き込み速度を確認した所、測定データ1GB・測定回数5回でやった所、シーケンシャルアクセスにて92MB・ランダムアクセス(4KB)にて100MB/Secという結果で、その他のランダムアクセス時には1MB/Secしか書き込みスピードが出ない状況です。 現在は、開発用のSDKにて書き込みを行っておりますが、調べた情報によると、C言語の mallocにて連続領域が確保できるという事ですので、C言語での書き込みを行えれば、書き込みによるボトルネックを無くせる可能性があると考えますので、やってみます。 勘違いにて、お騒がせしてしまい申し訳ありません。
Chironian

2016/07/06 13:28

> 大変申し訳ありません。私の勘違いで桁が一つ違い、、0.1Gbyte/Secでした。 > しかも、ざっくり書きすぎました。1フレーム2MBで、実際には60MB/Secです。 なるほど。60MBytes/Secなら、他にガンガンHDDを使っているものがなく、最近の高速なHDDなら対応できても良い気がします。 CrystalDiskMark 3のランダムアクセス(512KBytes)の値が60MBytes/Secを十分に超えていたら対応できる可能性があると思います。 スレッドの優先順位を一番高くする、ポーリングを行わないことが重要です。 > シーケンシャルアクセスにて92MB・ランダムアクセス(4KB)にて100MB/Secという結果で、その他のランダムアクセス時には1MB/Sec 見慣れない結果ですね。 価格comのHDDのレビューを見るとHDDのCrystalDiskMark計測値を載せている人が多いので参考になると思いますよ。
TEC_S

2016/07/07 02:14

ご回答ありがとうございます。 スレッドの優先順位を一番高くする・ポーリングを行わないの2項目、しっかりと考慮に入れたいと思います。 スレッドの優先順位については、①画像取得用 ②保存用という順位で進めたいと思いますが、考え方はあっていますでしょうか? >CrystalDiskMark 3のランダムアクセス(512KBytes)の値が60MBytes/Secを十分に超え >ていたら対応できる可能性があると思います。 ランダムアクセス(512KBytes)の値を参考にする・・・という事、承知しました。 mallocなどによる連続領域の確保をしても、書き込み時はランダムアクセスした場所へ書き込むから、512KBytesを参考にする・・・という理解で宜しいでしょうか。 大変恐縮ですが、CystalDiskMarkの参考の仕方、教えて頂けると幸いです。 宜しくお願い致します。
Chironian

2016/07/07 02:48

> スレッドの優先順位については、①画像取得用 ②保存用という順位で進めたいと思いますが、考え方はあっていますでしょうか? 「②保存処理用 >①画像取得用 > その他の処理」とすることをお薦めします。 保存処理自体はほとんどCPUを使いません。その周辺処理でCPUを多量に使う処理(例えば文字列検索的な処理など)をしなければ保存処理全体としてCPUをほとんど使わないことになります。その場合、優先順位を上げても他の処理の足を引っ張ることはまずありません。できるだけ応答性を上げることで保存が間に合わない問題を起きにくくします。 その結果、もし、画像取得が間に合わない時は何か考えないといけませんが、経験的には大丈夫ではないかと思います。 > mallocなどによる連続領域の確保をしても、書き込み時はランダムアクセスした場所へ書き込むから、512KBytesを参考にする・・・という理解で宜しいでしょうか。 その通りです。メモリ上で連続していることとHDD上で連続していることの間に関連はありません。 WindowsのNTFSはデータをできるだけ連続領域に書き込んでくれますが、管理領域の書き換えも必要ですから、どうしても時々シークが発生します。なので512KBytesランダム書き込みが比較的実際に近い値になるようです。 CrystalDiskMarkの512KBytesランダム書き込みが例えば80MBytes/Secでていた場合、実際にその程度の速度でファイル保存されることを期待できます。 ただし、TEC_SNさんのプログラムのファイル保存処理のアルゴリズムをCrystalDiskMarkの計測アルゴリズムが完全にシミュレートするわけではありませんから、あくまでも目安です。どの程度の差が出るのかは実際に計測してみるしかないです。 あ、思い出しました。HDDをデフラグしておいた方がより高速になります。 HDDの運用期間が長いとフラグメントが酷いことになるため連続領域を確保できず、書き込み性能が4KBytesランダムへ向かって段々下がって行きます。
TEC_S

2016/07/07 12:47

>「②保存処理用 >①画像取得用 > その他の処理」とすることをお薦めします。 ありがとうございます。 理由まで明確に教えて頂けたので、どう考えれば良いのか、かなり参考になります。 HDDのデフラグ、ありがとうございます。 参考にしつつ、SSDも試しつつも、進めたいと思います。 遅延の原因・対処について、ご教授頂けたと思いますので、回答としたいと考えます。 ありがとうございました。
guest

0

すでに他の方の回答にありますが、物理的にHDDへの転送速度が足りていないので、スレッドやキャッシュで解決できる問題ではありません。したがって、元の画像データを1bitたりとも欠けることなくHDDに保存したいというのであれば、不可能と言わざるを得ません。

もし、多少の劣化を許容するのであれば、画像データを圧縮しながらHDDに書き込むことで毎秒30フレームでの記録が可能になるかもしれません。Jpegなら高画質でも10分の1程度にはなります。毎秒100MB程度であれば十分現実的だと思います。ただしリアルタイムに変換できるかどうか判りませんが。

あるいは、おそらく元データはRGB888でしょうから、YUV420に変換してビット数を落とすだけでもなんとかなるかもしれません。YUV420だと1画素あたり12bitなので、4K画像なら1枚12.4MB、30フレームで370MB。SSDならたぶんいけると思います。

投稿2016/07/06 09:01

編集2016/07/06 09:03
catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TEC_S

2016/07/06 13:01

ご回答ありがとうございます。 他の回答者様へのコメントにて記載をさせて頂きましたが、私の勘違いにより、データのサイズが違っておりましたので、訂正させて頂きます。 HDDへの書き込み速度による遅延というのは変わらなそうなため、そちらについては対策できるよう進めたいと思います。申し訳ありませんでした。
catsforepaw

2016/07/06 13:39

そういうことでしたか。2MBの画像を毎秒30フレーム(60MB/sec)であれば、いけそうな気はします。あまり余裕はなさそうですが。 スレッドは、画像を取得するスレッドと、ストレージに保存するスレッドの二つで足りると思います。遅延したかどうかで処理を分ける必要はありません。というか、分けたところで無意味です。書き込みが遅延するということは転送速度が足りていないということなので、どうやっても書き込めないからです。その場合、処理を失敗させるか、データを捨てて継続するかのどちらかになります。 たぶんSSDなら余裕でしょう。HDDでもRAID0を組めば余裕ができると思います。 ただし、 > ①空ループにて遅延用リストを監視 これはやってはいけません。無駄にCPUに負荷をかけるだけです。イベント待ちをさせるようにしてください。
TEC_S

2016/07/07 02:07

空ループでの監視、やってはいけないんですね。 CPUに負荷を掛けていただけとは・・・大変勉強になりました。ありがとうございます。 また、本件遅延に関するご回答もありがとうございます。 書き込みの遅延は、スレッドなどで分けても無意味という事、自分だけでやっていてはその考えに至りませんでした。転送速度をどうするか、SSDへの変更も視野に入れ考えていこうと思います。
guest

0

想像ですが、その仕様を満たすには、相当なハードスペックが要求される気がします。
1秒間に1GBですか?1フレーム1GB?
仮に1秒間に1GBだとします。
今適当に調べたなんか速そうなSSDでも、書き込み速度616MB/Sです。
http://buffalo.jp/products/catalog/storage/ssd-wat/

書き込み量に対してハード側が追い付いていないので、ある程度はメモリにキャッシュされるけど、いずれ破綻しているのでは。
ドライブを分散するとか、RAIDを組むとか、メモリを大量に載せるとか、そんなことしないといけないんじゃないかなと想像してしまいます。

投稿2016/07/06 06:31

ttyp03

総合スコア16996

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TEC_S

2016/07/06 06:51

早期のご回答、ありがとうございます。 分かりにくい書き方で申し訳ありません。 1秒間に1GB程度です。 メモリは8GBのPCにて動作させるように考えていますが、もっと乗せることも視野に入っています。メモリを大量に・・・という事で思い出しましたが、Visual Studioのソフト作成はWin32にて行っていました。こちら、64bit用にすれば、もう少しメモリを使える量が多くなるという認識です。 ご指摘頂いた通り、メモリへのキャッシュが破綻しているのであれば、少しは改善するように思いましたので、やってみます。
yohhoy

2016/07/06 06:59 編集

ttyp03さんが指摘しているのは、メモリへのキャッシュ破綻ではなく、本質的にドライブへの書き出し速度が間に合っていないのではという点と思います。いくらメモリを増やしても、ドライブ書き出しが間に合わなければいずれはデータを欠損します。 1秒あたり1GByte(8Gbps)のデータ量となると4Kサイズを超える解像度でしょうか。これ級のデータを記録するとなると、ハードウェア的にはSSDx2~3台のRAID0はほぼ必須になるでしょう。
TEC_S

2016/07/06 08:19

ご指摘、ありがとうございます。 確かに、思い違いをしていました。そういう事ですね。 ボトルネックが、ファイルへの書き出しという事は理解していたのですが、その改善方法として、違うスレッドにて分散すれば良いと考えていた、考え方が違うのだと気づきました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問