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

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

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

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

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

Win32 API

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

マルチスレッド

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

C++

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

Q&A

解決済

1回答

2768閲覧

別スレッド内でのキューのポストや割り込みの方法

Weapon

総合スコア106

C

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

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

Win32 API

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

マルチスレッド

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

C++

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

0グッド

0クリップ

投稿2019/03/23 14:36

編集2019/03/23 14:42

前提・実現したいこと

ウィンドウのメインループを利用しているときにキューの割り込みをさせたい?ときはPostMessageではなくSendMessageを使うと思いますが以下のコードのような別スレッドでキューの割り込みをさせるにはどうすればいいのでしょうか?("SendThreadMessage"などというものはないですし)
また別スレッドのキューが自身のキューにメッセージを投げるときPostThreadMessageを使い第一引数のスレッド識別子はグローバル定義するしかないのでしょうか?

別スレッド内でWGLの描画を60fps(16ms)おきにWM_TIMERを受け取って行うコードです.以下ではWM_TIMERが来た時に再描画でTM_PAINTを呼ぶためgoto文をとりあえず使っています.

該当のソースコード

C

1//main.cpp 2#define UNICODE 3 4#include <windows.h> 5#include <process.h> 6#include "GLLoop.h" 7 8LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); 9 10const wchar_t CLASS_NAME[] = L"CLASS"; 11 12int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR nCmdLine, int nCmdShow) { 13 UNREFERENCED_PARAMETER(hPrevInstance); 14 UNREFERENCED_PARAMETER(nCmdLine); 15 16 WNDCLASSEX wc = { 17 sizeof(WNDCLASSEX),CS_VREDRAW | CS_HREDRAW, WindowProc, 18 0, 0, hInstance, 19 NULL, (HCURSOR)LoadCursor(NULL,IDC_ARROW), (HBRUSH)GetStockObject(WHITE_BRUSH), 20 NULL, CLASS_NAME, NULL 21 }; 22 23 RegisterClassEx(&wc); 24 25 HWND hwnd = CreateWindowEx( 26 WS_EX_LAYERED, CLASS_NAME, L"Template", WS_OVERLAPPEDWINDOW, 27 50, 50, 960, 525, 28 NULL, NULL, hInstance, NULL 29 ); 30 SetLayeredWindowAttributes(hwnd, 0x0, 0, LWA_COLORKEY); 31 32 ShowWindow(hwnd, nCmdShow); 33 UpdateWindow(hwnd); 34 35 MSG msg = {}; 36 37 while (GetMessage(&msg, NULL, 0, 0) != 0) { 38 TranslateMessage(&msg); 39 DispatchMessage(&msg); 40 } 41 42 return (int)msg.wParam; 43} 44 45LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 46 static unsigned thId; 47 static RECT rc; 48 static HANDLE ht; 49 switch (uMsg) { 50 case WM_ERASEBKGND: 51 return -1; 52 53 case WM_CREATE: 54 { 55 static PassHandle mph; 56 mph.hwnd = hwnd; 57 ht = (HANDLE)_beginthreadex(NULL, 0, (_beginthreadex_proc_type)GLLoop, &mph, 0, &thId); 58 59 DWORD dwExCode; 60 while (GetExitCodeThread(ht, &dwExCode) && dwExCode == STILL_ACTIVE && !PostThreadMessage(thId, WM_NULL, 0, 0))Sleep(1); 61 62 PostThreadMessage(thId, TM_CREATE, 0, 0); 63 } 64 break; 65 66 case WM_PAINT: 67 { 68 PostThreadMessage(thId, TM_PAINT, 0, 0); 69 PAINTSTRUCT ps = {}; 70 BeginPaint(hwnd, &ps); 71 EndPaint(hwnd, &ps); 72 } 73 break; 74 75 case WM_SIZE: 76 { 77 GetClientRect(hwnd, &rc); 78 PostThreadMessage(thId, TM_SIZE, 0, MAKELPARAM(rc.right - rc.left, rc.bottom - rc.top)); 79 } 80 break; 81 82 case WM_DESTROY: 83 { 84 PostThreadMessage(thId, TM_DESTROY, 0, 0); 85 WaitForSingleObject(ht, INFINITE); 86 PostQuitMessage(0); 87 } 88 return 0; 89 } 90 91 return DefWindowProc(hwnd, uMsg, wParam, lParam); 92}

C

1//GLLoop.h 2#pragma once 3 4#pragma comment(lib,"opengl32.lib") 5#pragma comment(lib,"glu32.lib") 6 7#include <Windows.h> 8#include <windowsx.h> 9#include <process.h> 10#include <gl/GL.h> 11#include <gl/GLU.h> 12 13#define TM_CREATE WM_APP + WM_CREATE 14#define TM_DESTROY WM_APP + WM_DESTROY 15#define TM_SIZE WM_APP + WM_SIZE 16#define TM_PAINT WM_APP + WM_PAINT 17 18typedef struct _tagPassHandle{ 19 HWND hwnd; 20}PassHandle; 21 22DWORD WINAPI GLLoop(LPDWORD lpdata);

C

1//GLLoop.cpp 2#ifndef UNICODE 3#define UNICODE 4#endif UNICODE 5 6#include "GLLoop.h" 7 8HWND thwnd; 9 10HDC hdc; 11HGLRC glrc; 12int tWidth; 13int tHeight; 14 15GLfloat radius = 0; 16GLfloat latitude, longitude, latinc, longinc; 17 18DWORD WINAPI GLLoop(LPDWORD lpdata) { 19 20 PassHandle *ph = (PassHandle *)lpdata; 21 22 thwnd = ph->hwnd; 23 24 MSG tMsg = {}; 25 while (GetMessage(&tMsg, NULL, 0, 0) > 0) { 26 switch (tMsg.message) { 27 case TM_CREATE: 28 { 29 hdc = GetDC(thwnd); 30 31 PIXELFORMATDESCRIPTOR pfd = { 32 sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_COLORINDEX, 33 8, 34 0, 0, 0, 0, 0, 0, 0, 0, 35 0, 36 0, 0, 0, 0, 37 16, 0, 0, 0, 0, 38 0, 0, 0 39 }; 40 41 int format = ChoosePixelFormat(hdc, &pfd); 42 43 if (format == 0) { 44 MessageBox(thwnd, L"Failed to ChoosePixxelFormat", L"CAUTION", MB_OK); 45 break; 46 } 47 48 if (SetPixelFormat(hdc, format, &pfd) == FALSE) { 49 MessageBox(thwnd, L"Failed to SetPixxelFormat", L"CAUTION", MB_OK); 50 break; 51 } 52 53 glrc = wglCreateContext(hdc); 54 55 if (glrc == NULL) { 56 MessageBox(thwnd, L"Failed to wglCreateContext", L"CAUTION", MB_OK); 57 break; 58 } 59 60 wglMakeCurrent(hdc, glrc); 61 62 63 glClearIndex((GLfloat)0); 64 65 glClearDepth(1.0); 66 67 glEnable(GL_DEPTH_TEST); 68 69 glMatrixMode(GL_PROJECTION); 70 71 GLfloat aspect = (GLfloat)tWidth / tHeight; 72 73 gluPerspective(45.0, aspect, 3.0, 7.0); 74 75 glMatrixMode(GL_MODELVIEW); 76 77 radius = 3.0 + 7.0 / 2.0; 78 79 80 latitude = 0; 81 longitude = 5.0; 82 latinc = 0.5; 83 longitude = 0; 84 85 SetTimer(NULL, 1, 16, 0); 86 } 87 break; 88 89 case TM_PAINT: 90 { 91 redraw: 92 93 GLUquadricObj *quadObj; 94 95 glNewList(1, GL_COMPILE); 96 97 quadObj = gluNewQuadric(); 98 99 gluQuadricDrawStyle(quadObj, GLU_LINE); 100 101 gluSphere(quadObj, 1.5, 16, 16); 102 103 glEndList(); 104 105 106 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 107 108 glPushMatrix(); 109 110 glTranslated(0.0, 0.0, -radius); 111 glRotated(0, 0.0, 0.0, 1.0); 112 glRotated(-latitude, 1.0, 0.0, 0.0); 113 glRotated(longitude, 0.0, 0.0, 1.0); 114 115 glIndexi(13); 116 glCallList(3); 117 118 glIndexi(16); 119 glCallList(1); 120 121 glIndexi(14); 122 glPushMatrix(); 123 glTranslatef(0.8f, -0.65F, .0f); 124 glRotatef(30.0f, 1.0f, 0.5f, 1.0f); 125 glCallList(2); 126 glPopMatrix(); 127 glPopMatrix(); 128 129 SwapBuffers(hdc); 130 } 131 break; 132 133 case TM_SIZE: 134 { 135 tWidth = GET_X_LPARAM(tMsg.lParam); 136 tHeight = GET_Y_LPARAM(tMsg.lParam); 137 138 glViewport(0, 0, tWidth, tHeight); 139 140 GLfloat aspect = (GLfloat)tWidth / tHeight; 141 142 glMatrixMode(GL_PROJECTION); 143 glLoadIdentity(); 144 gluPerspective(45.0, aspect, 3.0, 7.0); 145 glMatrixMode(GL_MODELVIEW); 146 147 } 148 break; 149 150 case WM_TIMER: 151 { 152 latitude += latinc; 153 longitude += longinc; 154 155 goto redraw; 156 } 157 break; 158 159 case TM_DESTROY: 160 { 161 wglDeleteContext(glrc); 162 ReleaseDC(thwnd, hdc); 163 164 _endthreadex(0); 165 } 166 break; 167 } 168 } 169 170 return 0; 171}

補足情報

Windows10 Pro
VisualStudio2017 Community

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

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

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

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

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

guest

回答1

0

ベストアンサー

ウィンドウのメインループを利用しているときにキューの割り込みをさせたい?ときはPostMessageではなくSendMessageを使うと思いますが以下のコードのような別スレッドでキューの割り込みをさせるにはどうすればいいのでしょうか?("SendThreadMessage"などというものはないですし)

多少の勘違いがあると思いました。SendMessage は同一スレッドで呼び出す場合、メッセージキューを介さずに直接ウィンドウプロシージャが呼び出されるため、割り込んでいるような印象を与えます。しかし、異なるスレッドで呼び出した場合、メッセージキューに該当メッセージがキューイングされるため、割り込み処理のようにはなりません。そのため、例えばスレッド側でメッセージ受信用ウィンドウを作成してそこに SendMessage したとしても割り込み処理のようにはなりません。

現在の作りに対する根本的な話になりますが、サブスレッドにメッセージキューを持たせる必要はありません。メッセージキューはウィンドウメッセージを処理するには都合が良いですが、繰り返し処理を実行するのには理想的な構造とは言えません。実際にはメインウィンドウとのやり取りはフラグ変数だけで済みます。とは言いつつもメッセージでやり取りした方が都合が良い部分もあります。私が描画処理を実装するなら以下のような構造になります。

C++

1//GLLoop.cpp 2#ifndef UNICODE 3#define UNICODE 4#endif UNICODE 5 6#include "GLLoop.h" 7 8 9DWORD WINAPI GLLoop(LPDWORD lpdata) { 10 11 PassHandle *ph = (PassHandle *)lpdata; 12 HWND thwnd = ph->hwnd; 13 14 HDC hdc; 15 HGLRC glrc; 16 int tWidth; 17 int tHeight; 18 19 GLfloat radius = 0; 20 GLfloat latitude = 0, longitude = 0, latinc = 0, longinc = 0; 21 22 // case TM_CREATE: に相当 23 { 24 RECT rc; 25 26 GetClientRect(thwnd, &rc); 27 tWidth = rc.right - rc.left; 28 tHeight = rc.bottom - rc.top; 29 30 hdc = GetDC(thwnd); 31 32 PIXELFORMATDESCRIPTOR pfd = { 33 sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_COLORINDEX, 34 8, 35 0, 0, 0, 0, 0, 0, 0, 0, 36 0, 37 0, 0, 0, 0, 38 16, 0, 0, 0, 0, 39 0, 0, 0 40 }; 41 42 int format = ChoosePixelFormat(hdc, &pfd); 43 44 if (format == 0) { 45 MessageBox(thwnd, L"Failed to ChoosePixxelFormat", L"CAUTION", MB_OK); 46 _endthreadex(1); 47 return 1; 48 } 49 50 if (SetPixelFormat(hdc, format, &pfd) == FALSE) { 51 MessageBox(thwnd, L"Failed to SetPixxelFormat", L"CAUTION", MB_OK); 52 _endthreadex(1); 53 return 1; 54 } 55 56 glrc = wglCreateContext(hdc); 57 58 if (glrc == NULL) { 59 MessageBox(thwnd, L"Failed to wglCreateContext", L"CAUTION", MB_OK); 60 _endthreadex(1); 61 return 1; 62 } 63 64 wglMakeCurrent(hdc, glrc); 65 66 67 glClearIndex((GLfloat)0); 68 69 glClearDepth(1.0); 70 71 glEnable(GL_DEPTH_TEST); 72 73 glMatrixMode(GL_PROJECTION); 74 75 GLfloat aspect = (GLfloat)tWidth / tHeight; 76 77 gluPerspective(45.0, aspect, 3.0, 7.0); 78 79 glMatrixMode(GL_MODELVIEW); 80 81 radius = 3.0 + 7.0 / 2.0; 82 83 84 latitude = 0; 85 longitude = 5.0; 86 latinc = 0.5; 87 longitude = 0; 88 } 89 90 MSG tMsg = {}; 91 DWORD lasttick = GetTickCount(); 92 93 while (true) { 94 95 while (PeekMessage(&tMsg, NULL, 0, 0, PM_REMOVE) > 0) 96 { 97 switch (tMsg.message) 98 { 99 case TM_SIZE: 100 { 101 tWidth = GET_X_LPARAM(tMsg.lParam); 102 tHeight = GET_Y_LPARAM(tMsg.lParam); 103 104 glViewport(0, 0, tWidth, tHeight); 105 106 GLfloat aspect = (GLfloat)tWidth / tHeight; 107 108 glMatrixMode(GL_PROJECTION); 109 glLoadIdentity(); 110 gluPerspective(45.0, aspect, 3.0, 7.0); 111 glMatrixMode(GL_MODELVIEW); 112 } 113 break; 114 case TM_DESTROY: 115 goto end; 116 } 117 } 118 119 DWORD now = GetTickCount(); 120 if (16 - (int)(now - lasttick) > 0) 121 { 122 Sleep(16 - (now - lasttick)); 123 } 124 125 // case TM_TIMER: 126 { 127 latitude += latinc; 128 longitude += longinc; 129 } 130 131 // case TM_PAINT: 132 { 133 GLUquadricObj *quadObj; 134 135 glNewList(1, GL_COMPILE); 136 137 quadObj = gluNewQuadric(); 138 139 gluQuadricDrawStyle(quadObj, GLU_LINE); 140 141 gluSphere(quadObj, 1.5, 16, 16); 142 143 glEndList(); 144 145 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 146 147 glPushMatrix(); 148 149 glTranslated(0.0, 0.0, -radius); 150 glRotated(0, 0.0, 0.0, 1.0); 151 glRotated(-latitude, 1.0, 0.0, 0.0); 152 glRotated(longitude, 0.0, 0.0, 1.0); 153 154 glIndexi(13); 155 glCallList(3); 156 157 glIndexi(16); 158 glCallList(1); 159 160 glIndexi(14); 161 glPushMatrix(); 162 glTranslatef(0.8f, -0.65F, .0f); 163 glRotatef(30.0f, 1.0f, 0.5f, 1.0f); 164 glCallList(2); 165 glPopMatrix(); 166 glPopMatrix(); 167 168 SwapBuffers(hdc); 169 170 lasttick = now; 171 } 172 } 173end: 174 175 // case TM_DESTROY: 176 { 177 wglDeleteContext(glrc); 178 ReleaseDC(thwnd, hdc); 179 _endthreadex(0); 180 } 181 182 return 0; 183}

実際にシステムを作成する場合、時間計測部分は GetTickCount ではなくハイパフォーマンスカウンタやマルチメディアタイマ等を使用し高精度に待ち時間を計測し、PeekMessage と Sleep 部分は MsgWaitForMultipleObjects を使用して効果的に待ち合わせるため、もうちょっと複雑な構造になります。上記の例は FPS の維持と制御を説明するための簡易的なサンプルです。

また別スレッドのキューが自身のキューにメッセージを投げるときPostThreadMessageを使い第一引数のスレッド識別子はグローバル定義するしかないのでしょうか?

static 変数に格納すればグローバル定義にはなりませんが、そういうことを尋ねたいのではないと推測して回答します。メインウィンドウに関連付けた値として管理するという手法があります。WNDCLASSEX 構造体の cbWndExtra に拡張メモリのサイズを指定して領域を確保し、その領域に対して SetWindowLong/GetWindowLong で値をやり取りするという方法があります。詳細はネットで調べてもらったらやり方が出てくると思います。あとは、MFC や ATL/WTL 等のフレームワークを使用するとすっきりデータがまとめられると思います。この辺もとりあえずはネットで調べてもらった方が良いですね。

ただし、何らかの値を関数を超えて保持しようとする限り、どのような手法を使用しても静的にメモリを確保していることには変わりません。その上で作成しようとしているプログラムに対して最適な手法を選択することになります。

投稿2019/03/23 17:10

atata0319

総合スコア881

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問