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

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

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

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

C++

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

Q&A

解決済

1回答

477閲覧

std::future,std::asyncを使った非同期で読み込んだ画像が描画されない原因が知りたい

samidare_chan

総合スコア15

マルチスレッド

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

C++

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

0グッド

0クリップ

投稿2024/01/03 09:47

編集2024/01/03 12:00

質問内容

提示コードのvoid Engine::SpriteRenderer::Render()関数部ですがSDL_Texture* texture = IMG_LoadTexture(Context::GetRenderer(),"./tile4.png");を使うと正常に描画できるのですがsprite.handleを使って描画すると描画されません。これはなぜでしょうか? 非同期で画像ロードしてしっかりと待機していて同じポインターを指しているのですが原因がわかりません。デストラクタ等は定義、宣言していません。

知りたいこと

画像が描画できない原因が知りたい

確認したいこと

SDL_GetError()を実行しましたが何も表示されていません。

#ソースコード 全文

画像ロード関数

cpp

1#include <iostream> 2#include <Context.hpp> 3#include <vector> 4#include <functional> 5#include <future> 6#include <iostream> 7#include <glm/glm.hpp> 8#include <thread> 9#include <mutex> 10#include <condition_variable> 11#include <chrono> 12#include <random> 13#include <thread> 14 15struct Sprite 16{ 17 SDL_Texture *handle; 18 std::string path; 19}; 20 21 22std::vector<Sprite> sprites; //ロードした画像リスト 23std::vector<std::string> nowLoad; //現在ロード中の画像リスト 24std::mutex loadMutex; 25std::condition_variable loadCV; 26 27std::chrono::_V2::system_clock::time_point startTime; 28 29void SetStartTime() 30{ 31 startTime = std::chrono::high_resolution_clock::now(); 32} 33 34int GetEndTime() 35{ 36 37 auto endTime = std::chrono::high_resolution_clock::now(); 38 auto time = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime); 39 40 return time.count(); 41} 42 43/*############################################################## 44# 乱数取得 45##############################################################*/ 46int GetRandom(int rand) 47{ 48 // 現在の時間を取得して種(seed)として使用する 49 auto now = std::chrono::high_resolution_clock::now(); 50 auto seed = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count(); 51 52 // 乱数生成器を初期化 53 std::mt19937_64 generator(seed); 54 55 // ミリ秒単位の乱数を生成 56 std::uniform_int_distribution<int> distribution(0, rand); 57 int random_number = distribution(generator); 58 59 //std::cout << "ミリ秒単位の乱数: " << random_number << std::endl; 60 61 return random_number; 62} 63 64/*############################################################## 65 66# 非同期 版 67 68# スプライトロード関数  69※ テスト用のためロード時間を乱数でミリ秒待機 70##############################################################*/ 71Sprite LoadSprite(const char* filePath) 72{ 73 std::unique_lock<std::mutex> lock(loadMutex); 74 75 // 他のスレッドが同じ画像をロード中であれば待機 76 loadCV.wait(lock, [&filePath]() 77 { 78 for(const std::string& path : nowLoad) 79 { 80 if (path == std::string(filePath)) 81 { 82 return false; 83 } 84 } 85 86 return true; 87 }); 88 89 //スプライトリストから取り出す 90 for (const Sprite& s : sprites) 91 { 92 if (s.path == std::string(filePath)) 93 { 94 std::cout << "found sprite" << std::endl; 95 return s; 96 } 97 } 98 99 std::cout << "new sprite" << std::endl; 100 101 // ロード中の画像リストに追加 102 nowLoad.push_back(std::string(filePath)); 103 lock.unlock(); // ロックを解除して他のスレッドがロードを開始できるようにする 104 105 //画像ロード 106// int milliseconds = 1000; 107 //int milliseconds = GetRandom(1000); 108// std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); 109 SDL_Texture *texture = IMG_LoadTexture(Engine::Context::GetRenderer(),"tile4.jpg"); 110 111 lock.lock(); // ロックを再取得して安全に状態を更新する 112 113 114 //ロードが終わったためリストから削除 115 int i = 0; 116 for(const std::string& s : nowLoad) 117 { 118 if(s == filePath) 119 { 120 break; 121 } 122 123 i++; 124 } 125 nowLoad.erase(nowLoad.begin() + i); 126 127 //ロード済みスプライトリストに追加 128 sprites.push_back(Sprite{texture, std::string(filePath) }); 129 //sprites.push_back(Sprite{ milliseconds, std::string(filePath) }); 130 131 // 画像のロードが完了したことを通知 132 loadCV.notify_all(); 133 134 return sprites.back(); 135} 136 137/*############################################################## 138 139# 同期 版 140 141# スプライトロード関数  142※ テスト用のためロード時間を乱数でミリ秒待機 143##############################################################*/ 144 145 146/*############################################################## 147# Component 基底 148##############################################################*/ 149class GameObject; 150class Component 151{ 152public: 153 154GameObject *gameObject; 155 Component(GameObject* g) 156 { 157 gameObject = g; 158 } 159 160 virtual std::vector<std::future<void>> PreLoad() 161 { 162 163 return std::move(futures); 164 } 165 166 167 virtual void Start() = 0; 168 169 virtual void Update() = 0; 170 171 virtual void Render() 172 { 173 174 } 175 176protected: 177 178 std::vector<std::future<void>> futures; 179}; 180/*############################################################## 181# GameObject 基底 182##############################################################*/ 183class GameObject 184{ 185public: 186 187 GameObject() 188 { 189 190 } 191 192 std::vector<std::future<void>> getPreLoad() 193 { 194 std::vector<std::future<void>> process; 195 196 for(Component *c : components) 197 { 198 for(std::future<void> &f : c->PreLoad()) 199 { 200 process.push_back(std::move(f)); 201 } 202 } 203 204 return std::move(process); 205 } 206 207 208 void Start() 209 { 210 for(Component* c : components) 211 { 212 c->Start(); 213 } 214 } 215 void Update() 216 { 217 for(Component* c : components) 218 { 219 c->Update(); 220 } 221 } 222 223 void Render() 224 { 225 for(Component* c : components) 226 { 227 c->Render(); 228 } 229 } 230 231 std::vector<Component*> components; 232}; 233 234/*############################################################## 235# Scene 基底 236##############################################################*/ 237class Scene 238{ 239public: 240 241 std::vector<GameObject*> gameObjects; 242 void PreaLoad() 243 { 244 std::vector<std::future<void>> futures; 245 for(GameObject *g : gameObjects) 246 { 247 for(std::future<void> &f : g->getPreLoad()) 248 { 249 futures.push_back(std::move(f)); 250 } 251 } 252 253 254 SetStartTime(); 255 for(std::future<void> &f : futures) 256 { 257 f.wait(); 258 } 259 260 int time = GetEndTime(); 261 std::cout<<time<<std::endl; 262 } 263 264 265 void Update() 266 { 267 for(GameObject *g : gameObjects) 268 { 269 g->Update(); 270 } 271 } 272 273 void Render() 274 { 275 for(GameObject *g : gameObjects) 276 { 277 g->Render(); 278 } 279 } 280 281 282}; 283 284/*############################################################## 285# SpriteRenderer コンポーネント 286##############################################################*/ 287class SpriteRenderer : public Component 288{ 289public: 290 291 Sprite sprite; 292 SpriteRenderer(GameObject* g): Component(g) 293 { 294 295 } 296 297 void Start() override 298 { 299 300 } 301 302 void Update() override 303 { 304 305 } 306 307 void Render() override 308 { 309 SDL_Texture* texture = IMG_LoadTexture(Engine::Context::GetRenderer(),"tile4.jpg"); 310 SDL_Rect rect = {0,0,64,64}; 311 SDL_Rect dest = {100,100,64,64}; 312 313 //std::cout<<"Render"<<std::endl; 314 //SDL_RenderCopy(Engine::Context::GetRenderer(),texture,&rect,&dest); 315 SDL_RenderCopy(Engine::Context::GetRenderer(),sprite.handle,&rect,&dest); 316 //SDL_RenderCopy(Engine::Context::GetRenderer(),sprite.handle,&rect,&dest); 317 318 std::cout<<SDL_GetError()<<std::endl; 319 } 320}; 321 322 323/*############################################################## 324# Control コンポーネント 325##############################################################*/ 326class SpriteRenderer; 327class Control : public Component 328{ 329public: 330 Control(GameObject *g): Component(g) 331 { 332 333 } 334 335 std::vector<std::future<void>> PreLoad() override 336 { 337 338 339 futures.push_back(std::async(std::launch::async,[this](){ ((SpriteRenderer*)(gameObject->components.at(0)))->sprite = LoadSprite("tile4.jpg"); })); 340 341 342 343 return std::move(futures); 344 } 345 346 void Start() 347 { 348 349 } 350 351 void Update() 352 { 353 354 } 355}; 356/*############################################################## 357# Player ゲームオブジェクト 358##############################################################*/ 359class Player : public GameObject 360{ 361public: 362 Player(): GameObject() 363 { 364 components.push_back(new SpriteRenderer(this)); 365 components.push_back(new Control(this)); 366 } 367 368 369 370 371}; 372 373 374 375 376/*############################################################## 377# Game シーン 378##############################################################*/ 379class Game : public Scene 380{ 381public: 382 Game(): Scene() 383 { 384 gameObjects.push_back(new Player()); 385 }; 386 387 388 void PreLoad() 389 { 390 for(std::future<void> &f : gameObjects.at(0)->getPreLoad()) 391 { 392 f.wait(); 393 } 394 } 395 396 void Start() 397 { 398 gameObjects.at(0)->Start(); 399 } 400 401 void Update() 402 { 403 404 gameObjects.at(0)->Update(); 405 } 406 407 void Render() 408 { 409 gameObjects.at(0)->Render(); 410 } 411}; 412 413 414 415 416int main() 417{ 418 Engine::Context::Init("Game",glm::ivec2(680,480)); 419 Game *g = new Game(); 420 421 g->PreLoad(); 422 423 g->Start(); 424 while(true) 425 { 426 Engine::Context::ClearBuffer(); 427 if(Engine::Context::GetKey(SDL_SCANCODE_ESCAPE) == true) 428 { 429 break; 430 } 431 432 433 g->Update(); 434 g->Render(); 435 436 Engine::Context::RenderBuffer(); 437 } 438 439 440 Engine::Context::Finalize(); 441 return 0; 442}

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

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

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

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

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

hiroki-o

2024/01/03 18:52 編集

手元の環境で再現して調査しようとしていますが、苦戦しています。 もし、お手数でなければ教えてください。 (一般的なstd::asyncの話として考えてほしい、というなら結構です) 1. OSとC++コンパイラは何を使用していますか? 2. Context.hppは、https://www.sfml-dev.org/index.php のSFMLでしょうか? 3. glmは、https://github.com/icaven/glm でしょうか? 4. SDLは、https://github.com/libsdl-org/SDL でしょうか? また、#include <SDL.h>は不要ですか? 5. IMG_LoadTextureクラス、Engineクラスは、どのヘッダーに属するクラスでしょうか?
fana

2024/01/05 04:36 編集

全く知らない物の話なので的外れかとも思いますが…… まず,やろうとしている処理というのがそもそもマルチスレッドで(というか「メインでないスレッドで」とでもいうか?)実施可能な処理なのか? というあたりは大丈夫なのでしょうか? 例えば…… 確か,OpenGLのレンダリングコンテキストはスレッド固有みたいな扱いだったと記憶しています. お使いのライブラリ(SDL?)に,それと似たような何らかの事柄が存在していたりはしないのだろうか? とか,ちょっと思いました. (SDLというやつが裏で何を(OpenGL? DirectX? その他?)用いているのか等全く知りませんが,SDLがそういったところを仕様として面倒見てくれる(マルチスレッドOKと保証してくれる)物なのだろうか? …みたいな?)
guest

回答1

0

自己解決

どうやらマルチスレッドでの処理の場合は以下の専用の処理が必要みたいです

原因

専用の処理を書く必要がある

参考サイト

参考サイト:https://www.libsdl.org/release/SDL-1.2.15/docs/html/thread.html

投稿2024/01/08 03:01

samidare_chan

総合スコア15

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問