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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

マルチスレッド

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

C++

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

Q&A

解決済

1回答

1136閲覧

WinAPI 子スレッドにおけるキューの取得・メッセージループ

Weapon

総合スコア106

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

マルチスレッド

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

C++

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

0グッド

0クリップ

投稿2018/12/19 08:43

前提・実現したいこと

WinAPI 子スレッドでの描画でキューを作りメッセージループとご教授いただいたのですが子スレッドにおいてキューはどうやって取得するのでしょうか?
メインウィンドウの場合GetMessageで取得してDispatchMessageからWindowProcにメッセージが渡っていたと思っていましたがこの場合のスレッドはウィンドウではないからWindowProcではないでしょうしスレッドの関数そのもののThreadProcとも違いますよね.
どのようにメッセージループを実装すればいいのでしょうか?

またプロシージャ内のswitch前,switch下(case前),グローバル宣言それぞれでstaticで変数宣言することにどのような違いがあるのでしょう?

発生している問題・エラーメッセージ

C

1//main 2#ifndef UNICODE 3#define UNICODE 4#endif UNICODE 5 6#include <windows.h> 7#include <process.h> 8#include "render thread.h" 9#include "Header.h" 10 11LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); 12LRESULT CALLBACK ChildWindowProc(HWND, UINT, WPARAM, LPARAM); 13 14HINSTANCE hInst; 15 16RECT rc; 17HWND chwnd; 18 19static unsigned thid; 20 21const wchar_t CLASS_NAME[] = L"CLASS"; 22const wchar_t CHILD_CLASS_NAME[] = L"CHILD_CLASS"; 23 24int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR nCmdLine, int nCmdShow) { 25 UNREFERENCED_PARAMETER(hPrevInstance); 26 UNREFERENCED_PARAMETER(nCmdLine); 27 28 hInst = hInstance; 29 30 WNDCLASSEX wc = { 31 sizeof(WNDCLASSEX),CS_VREDRAW | CS_HREDRAW, WindowProc, 32 0, 0, hInstance, 33 NULL, (HCURSOR)LoadCursor(NULL, IDC_ARROW),(HBRUSH)GetStockObject(GRAY_BRUSH), 34 NULL, CLASS_NAME, NULL 35 }; 36 37 RegisterClassEx(&wc); 38 39 HWND hwnd = CreateWindowEx( 40 0, CLASS_NAME, L"Template", WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN, 41 50, 50, 960, 525, 42 NULL, NULL, hInstance, NULL 43 ); 44 45 ShowWindow(hwnd, nCmdShow); 46 UpdateWindow(hwnd); 47 48 MSG msg = {}; 49 50 while (GetMessage(&msg, NULL, 0, 0)) { 51 TranslateMessage(&msg); 52 DispatchMessage(&msg); 53 } 54 55 return (int)msg.wParam; 56} 57 58LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 59 switch (uMsg) { 60 case WM_CREATE: 61 { 62 WNDCLASSEX wcx = { 63 sizeof(WNDCLASSEX),CS_VREDRAW | CS_HREDRAW, ChildWindowProc, 64 0, 0, hInst, 65 NULL, (HCURSOR)LoadCursor(NULL, IDC_ARROW),(HBRUSH)GetStockObject(WHITE_BRUSH), 66 NULL, CHILD_CLASS_NAME, NULL 67 }; 68 69 RegisterClassEx(&wcx); 70 71 chwnd = CreateWindowEx( 72 0, CHILD_CLASS_NAME, L"", WS_CHILD|WS_VISIBLE|WS_THICKFRAME, 73 0, 0, 0, 0, 74 hwnd, NULL, hInst, NULL 75 ); 76 77 ShowWindow(chwnd, SW_SHOW); 78 UpdateWindow(chwnd); 79 } 80 break; 81 82 case WM_SIZE: 83 { 84 GetClientRect(hwnd, &rc); 85 MoveWindow(chwnd, 5, (rc.bottom - rc.top - (rc.right - rc.left) / 2)/2, (rc.right - rc.left) / 2 - 5, (rc.right - rc.left) / 2 - 5, TRUE); 86 MoveWindow(form, (rc.right - rc.left) * 3 / 4 , 150, 100, 50, TRUE); 87 MoveWindow(button, (rc.right - rc.left) * 3 / 4 + 110, 150, 100, 50, TRUE); 88 } 89 break; 90 91 case WM_DESTROY: 92 PostQuitMessage(0); 93 return 0; 94 } 95 96 return DefWindowProc(hwnd, uMsg, wParam, lParam); 97} 98 99LRESULT CALLBACK ChildWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 100 switch (uMsg) { 101 static RENDTHDATA mrtd; 102 case WM_CREATE: 103 { 104 GetClientRect(GetParent(hwnd), &rc); 105 mrtd.hwnd = hwnd; 106 mrtd.hdc = GetDC(hwnd); 107 mrtd.size = (rc.right - rc.left) / 2 - 5; 108 109 wchar_t mess[1024] = { 0 }; 110 wsprintf(mess, L"HWND : %d\n HDC : %x\nSize : %d", mrtd.hwnd, mrtd.hdc, mrtd.size); 111 MessageBox(NULL, mess, L"Alert", MB_OK); 112 113 _beginthreadex(NULL, 0, (_beginthreadex_proc_type)render, &mrtd, 0, &thid); 114 PostThreadMessage(thid, WM_NULL, 0, 0); 115 116 } 117 break; 118 119 case WM_PAINT: 120 121 PostThreadMessage(thid, TM_PAINT, 0, 0); 122 break; 123 124 case WM_DESTROY: 125 PostThreadMessage(thid, TM_PAINT, 0, 0); 126 _endthreadex(0); 127 PostQuitMessage(0); 128 return 0; 129 } 130 131 DefWindowProc(hwnd, uMsg, wParam, lParam); 132}

C

1//Header.h 2#pragma once 3 4#include <windows.h> 5 6typedef struct _tagRENDTHDATA { 7 HWND hwnd; 8 HDC hdc; 9 int size; 10}RENDTHDATA; 11 12#define TM_CREATE (WM_APP+1) 13#define TM_DESTROY (WM_APP+2) 14#define TM_PAINT (WM_APP+3)

C

1//render thread.h 2#pragma once 3 4#define UNICODE 5#include <windows.h> 6 7DWORD WINAPI render(LPVOID);

C

1//render thread.cpp 2#define UNICODE 3 4#include <windows.h> 5#include "render thread.h" 6#include "Header.h" 7 8int width =10000; 9int height = 10000; 10 11DWORD WINAPI render(LPVOID lp) { 12 13 RENDTHDATA *rtd = (RENDTHDATA *)lp; 14 15 HWND hwnd = rtd->hwnd; 16 HDC hdc = rtd->hdc; 17 int size = rtd->size; 18 19 static MSG tMsg = {}; 20 21 while (GetMessage(&tMsg, hwnd, 0, 0)>0) { 22 switch (tMsg.message) { 23 static DWORD **image; 24 static DWORD *image_c; 25 static DWORD *dib; 26 static BITMAPINFO bmpi; 27 case TM_CREATE: 28 { 29 MessageBox(NULL, L"CALLED", L"Alert", MB_OK); 30 31 image = (DWORD**)malloc(sizeof(DWORD*)*width); 32 image_c = (DWORD*)malloc(sizeof(DWORD)*width*height); 33 for (int i = 0; i < width; i++)image[i] = image_c + i * height; 34 for (int i = 0; i < width; i++)for (int j = 0; j < height; j++)image[i][j] = 0x000000ff; 35 36 dib = (DWORD*)calloc(width*height, sizeof(DWORD)); 37 38 ZeroMemory(&bmpi, sizeof(bmpi)); 39 bmpi.bmiHeader.biSize = sizeof(bmpi); 40 bmpi.bmiHeader.biWidth = width; 41 bmpi.bmiHeader.biHeight = height; 42 bmpi.bmiHeader.biPlanes = 1; 43 bmpi.bmiHeader.biBitCount = 32; 44 bmpi.bmiHeader.biCompression = BI_RGB; 45 } 46 break; 47 48 case TM_PAINT: 49 { 50 for (int i = 0; i < width; i++)for (int j = 0; j < height; j++)dib[i + j * width] = image[height - j - 1][i]; 51 52 int a = StretchDIBits( 53 hdc, 0, 0, width, height, 0, 0, size, size, 54 dib, &bmpi, 55 DIB_RGB_COLORS, SRCCOPY 56 ); 57 } 58 break; 59 60 case TM_DESTROY: 61 { 62 free(dib); 63 free(image_c); 64 free(image); 65 } 66 break; 67 68 } 69 } 70 return 0; 71}

ちなみにMonte Carloの円周率導出を時間で徐々にプロットしていくというレンダリングのキャンバスを作ろうとしていました.
なおcase TM_PAINT1行目で行われているのは非効率ながらxy座標をDIBの線型配列に変換するものです.時間おきにプロット命令を入れるのでこの処理はcase TM_CREATEではしませんでした.プロット処理を追加したときはTM_TIMEなどを作成してそこを介してダブルバッファリングを考えています.

補足情報

Windows10 Pro
VisualStudio2017 Community

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

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

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

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

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

t_obara

2018/12/19 10:02

なぜスレッドで描画をしようとしているのか直前の記事で指摘されている通り疑問です。単にタイマーで徐々にプロットすれば良いのでは?スレッドをより深く学ぶためでしょうか?それなら題材としては筋が悪いので別な題材で学習することをお勧めします。
Weapon

2018/12/19 12:03

激しく切り替わる大きなイメージはボトルネックになるのではと別スレッドを使い描画するものだと思っていましたがならないものなのでしょうか?基本的にはタイマーで徐々に描きたいのではなくシミュレーションのようなものの描画過程を見るのが私の書きたいコードなのでタイマーによる手法は取りませんでした.どこまで処理を分散できるのかを考えてやってはいますが同期のほうがむしろボトルネックになるのならばメインスレッドにも目を向けて書いていこうと思います.しかしどこまで別スレッドでできるのかどこまでやるべきなのかほぼ理解していないのでまたその都度お願いします.
guest

回答1

0

ベストアンサー

メッセージを処理するスレッドとしては提示されているコードでほとんど問題ないレベルまでいってます。惜しいのが render thread.cpp の以下の部分

C++

1while (GetMessage(&tMsg, hwnd, 0, 0)>0)

で、これは特定のウィンドウからのメッセージを処理するわけではないので、以下のようになります。

C++

1while (GetMessage(&tMsg, NULL, 0, 0)>0)

この修正だけでスレッド間のメッセージ送受信は可能になります。
あとは DWM で処理されている現在では全く問題になりませんが、GetDC はなるべく HDC を使う直前で呼び出すのをお勧めします。DWM 導入以前はウィンドウを動かすとウィンドウのクライアント原点と GetDC した原点が異なるために描画位置がずれる問題がありました。まぁ、今では問題になることはありませんが・・・。

他にいろいろありますが、デバッグ中に気付くと思いますので割愛します。

またプロシージャ内のswitch前,switch下(case前),グローバル宣言それぞれでstaticで変数宣言することにどのような違いがあるのでしょう?

スコープが異なります。該当変数を使用できる範囲は以下のようになります。
・switch前のものは、直前の {} 内のみ
・switch下(case前)のものは switch の {} 内のみ
・グローバル宣言はそのファイル内で参照可能

投稿2018/12/19 16:23

編集2018/12/19 16:25
atata0319

総合スコア881

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

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

Weapon

2018/12/20 00:00

すこし話題からそれるようですが_endthreadexの引数 スレッド終了コードとは何ですか?
atata0319

2018/12/20 00:08

スレッドの呼び出し元がスレッドの終了コードを受けとるために渡す値ですね。呼び出し元は GetExitCodeThread で値を取得します。厳密にはスレッドハンドルがあればどのスレッドでも終了コードは取得できます。現在のコードではスレッドハンドルの方は扱っていないので取得する場合、スレッドハンドルも別途保管しておく必要がありますね。PostThreadMessageで使っているスレッドIDとは別物です。
Weapon

2018/12/20 00:45

ハンドルで終わらせたいスレッドを指定するのではなくハンドルから取得できる値を介してスレッドを終わらせるという認識でいいですか?
atata0319

2018/12/20 00:59

スレッドを終了させるのはスレッド自体のendthreadの呼び出しかスレッドの関数の終了です。GetExitCodeThreadはスレッドが終了した後で値を取得するのみです。終わらせる動作はありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問