April 25, 2024, 05:46:05 AM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Multithreading hickup question.

Started by J B Wood (Zumwalt), September 08, 2006, 09:06:19 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

J B Wood (Zumwalt)

September 08, 2006, 09:06:19 AM Last Edit: September 08, 2006, 09:31:25 AM by zumwalt
I thought at first I was doing something wrong, but then I took the code from Paul's Midi example that has multithreading in it and tried it with that, and got the same results.

What happens is that the window is created, when I try to start a new thread and get its ID, I loose the window that was initially created, it goes away, Aurora3d is still in memory.

Here is my code
(make sure to also have the midi example src included in your project)
This is a little more intermediate, and I am assuming you know about includes and source files.



//declare cdecl import, atan2(double y, double x),double;
#include "general.inc"

struct ObjThread
{
uint tThread;
uint stopEvent;
}

general :: general()
{

}

general :: _general()
{
}

general :: diff2time(int p1, int p2),int
{
int temp;
temp = p1 - p2;
return(temp);
}

general :: ThreadProc(int *param)
{
int h=*param;
//printf("%d Thread is Running!\n",h);
_endthread();
}

general :: TestThread(),uint
{
pointer pTemp,pReturn;
int nTemp;
pTemp=NEW(ObjThread,1);
*(ObjThread)pTemp.tThread=CreateThread(NULL,0,&ThreadProc,pTemp,CREATE_SUSPENDED,nTemp);
*(ObjThread)pTemp.stopEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
IF(*(ObjThread)pTemp.tThread <> NULL)
{
ResumeThread(*(ObjThread)pTemp.tThread);
pReturn = pTemp;
}
return pReturn;
}

general :: TerThread(uint p0),int
{
int temp=0;
temp=CloseHandle(p0);
}


Main application call from my main

uint TestThredResult;
int closedEvent;
General T;

// other initializations etc
s.CreateWindowed(0,0,1024,768,AWS_CAPTION|AWS_VISIBLE|AWS_SIZE,0,"Zumwalts 3D Test - ESC exits",NULL,false);

// Thread test..
TestThreadResult = T.testThread();
// window goes away at this point, but its running in memory and a thread has terminated that has the window in it, but my new thread is running.
s.RenderText(440,58,"Thread Tested, Result: "+NumToStr(TestThreadResult),RGBA(255,150,0,255));
s.RenderScene();
closedEvent = T.TerThread(TestThreadResult);
s.RenderText(440,70,"Thread Terminated: "+NumToStr(closedEvent),RGBA(255,150,0,255));
s.RenderScene();


J B Wood (Zumwalt)

Ok, here is the skinny, I HATE CALL STACKS

Paul, is it safe to say that when creating ANY objec, wether its a C3DMesh or int or whatever, we should give it default values for its members?

Right now, I am getting a threadID result and its closing, but the application crashes while running.
I have no clue where to look on this.

Ionic Wind Support Team

You should always initialize member variables in your constructor.

Variables in a subroutine are just memory locations and need to be initialized unless you're specifically assigning them a value from a return value.   Use the API function RtlZeroMemory if you need to initialize a structure to 0.

When using multithreading you have to syncronize access to shared resources, like global variables, or allocated memory, using mutexes or the like.  In other words block one thread from accessing the shared variable while the other is using it.  You probably haven't got that far yet.
Ionic Wind Support Team

J B Wood (Zumwalt)

Well doing some deeper debug and found out this so far:

general :: TestThread(),uint
{
pointer pTemp,pReturn;
int nTemp=0;
pTemp=NEW(ObjThread,1);
*(ObjThread)pTemp.tThread=CreateThread(NULL,0,&ThreadProc,pTemp,CREATE_SUSPENDED,nTemp);
*(ObjThread)pTemp.stopEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
IF(*(ObjThread)pTemp.tThread <> NULL)
{
ResumeThread(*(ObjThread)pTemp.tThread);
pReturn = pTemp;
CloseHandle(*(ObjThread)pTemp.tThread);
OutputDebugStringA("Thread is Closed!");
}
ELSE
{
pReturn = NULL;
}
return pReturn;
}


This code is being executed, the IF statement is running my outpus, and my debug window is telling me that the Thread is Closed! which suggested that tThread <> NULL.
Thread ID as an uint is always coming back as 1888944, and I do mean always.

After the routine is done I send a debug print of the thread result, here is the debug output.

Starting debug session...
Loading DLL: ntdll.dll
Loading DLL: C:\WINDOWS\system32\kernel32.dll
Loading DLL: C:\WINDOWS\system32\USER32.DLL
Loading DLL: C:\WINDOWS\system32\GDI32.dll
Loading DLL: C:\WINDOWS\system32\DINPUT.DLL
Loading DLL: C:\WINDOWS\system32\msvcrt.dll
Loading DLL: C:\WINDOWS\system32\ADVAPI32.dll
Loading DLL: C:\WINDOWS\system32\RPCRT4.dll
Loading DLL: C:\WINDOWS\system32\WINMM.dll
Loading DLL: C:\WINDOWS\system32\DX3D9R.DLL
Loading DLL: C:\WINDOWS\system32\d3d9.dll
Loading DLL: C:\WINDOWS\system32\d3d8thk.dll
Loading DLL: C:\WINDOWS\system32\VERSION.dll
Loading DLL: C:\WINDOWS\system32\MSVCP60.dll
Loading DLL: C:\WINDOWS\system32\CRTDLL.DLL
Loading DLL: C:\WINDOWS\system32\IMM32.DLL
Loading DLL: C:\WINDOWS\system32\uxtheme.dll
Loading DLL: C:\WINDOWS\system32\MSCTF.dll
Loading DLL: C:\WINDOWS\system32\SynTPFcs.dll
Loading DLL: C:\WINDOWS\system32\msctfime.ime
Loading DLL: C:\WINDOWS\system32\ole32.dll
Loading DLL: C:\WINDOWS\system32\usp10.dll
Loading DLL: C:\WINDOWS\system32\HID.DLL
Loading DLL: C:\WINDOWS\system32\SETUPAPI.DLL
Loading DLL: C:\WINDOWS\system32\WINTRUST.dll
Loading DLL: C:\WINDOWS\system32\CRYPT32.dll
Loading DLL: C:\WINDOWS\system32\MSASN1.dll
Loading DLL: C:\WINDOWS\system32\IMAGEHLP.dll
Thread is Closed!
Thread Result: 1888944
First chance exception: Address 0x0012FF78 Access Violation.
Final chance exception: Address 0x0012FF78 Access Violation.
The thread 0x1190 exited with code: 1
The thread 0x12E8 exited with code: 1
The program 'C:\Program Files\Aurora\projects\Aurora3d\Aurora3D.exe' exited with code: 1


I'll keep at it.

Ionic Wind Support Team

Closing the thread won't set your local varaible to NULL.


  ResumeThread(*(ObjThread)pTemp.tThread);
pReturn = pTemp;
CloseHandle(*(ObjThread)pTemp.tThread);
OutputDebugStringA("Thread is Closed!");
//add this
*(ObjThread)pTemp.tThread = NULL;


Ionic Wind Support Team

J B Wood (Zumwalt)

same error, this is what I have so far for my class:


#AUTODEFINE "OFF"
#include "general.inc"

general :: general()
{
nTemp=0;
pTemp=NEW(ObjThread,1);
}

general :: _general()
{
DELETE pTemp;
}

general :: diff2time(int p1, int p2),int
{
int temp;
temp = p1 - p2;
return(temp);
}

general :: ThreadProc(ObjThread *param)
{
RunProc(param);
}

SUB RunProc(ObjThread *param)
{
UINT hEvent = NULL;
OutputDebugStringA("Thread is Running!");
hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
CloseHandle(hEvent);
}

general :: TestThread(),uint
{
*(ObjThread)pTemp.tThread=CreateThread(NULL,0,&ThreadProc,pTemp,CREATE_SUSPENDED,nTemp);
*(ObjThread)pTemp.stopEvent=CreateEventA(NULL,FALSE,FALSE,NULL);
IF(*(ObjThread)pTemp.tThread <> NULL)
{
ResumeThread(*(ObjThread)pTemp.tThread);
pReturn = pTemp;
CloseHandle(*(ObjThread)pTemp.tThread);
OutputDebugStringA("Thread is Closed!");
*(ObjThread)pTemp.tThread = NULL;
DELETE pTemp;
}
ELSE
{
DELETE pTemp;
pReturn = NULL;
}
return pReturn;
}

general :: TerThread(uint p0),int
{
int temp=0;
temp=CloseHandle(p0);
}


This is my include:

#AUTODEFINE "OFF"
#define _INC_PROCESS
#define _CRTIMP
#define _CRTAPI1

#define _P_WAIT         0
#define _P_NOWAIT       1
#define _OLD_P_OVERLAY  2
#define _P_OVERLAY      2
#define _P_NOWAITO      3
#define _P_DETACH       4

#define _WAIT_CHILD      0
#define _WAIT_GRANDCHILD 1

// Reference: http://msdn2.microsoft.com/en-us/library/kdzttdcb.aspx
// handle = _beginthread(method name, 0, null)
declare cdecl import, _beginthread(Pointer p0,uint p1, Pointer p2),uint;
declare cdecl import, _endthread();
declare cdecl import, _beginthreadex(void *p0, uint p1, uint *p2, void *p3, uint p4, uint *p5),Handle;
declare cdecl import, _endthreadex(uint p0);

declare cdecl import, abort();
declare cdecl import, exit(int p0);
declare cdecl import, _exit(int p1);

//declare cdecl import, WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds),DWORD;
declare cdecl import, WaitForMultipleObjects(DWORD nCount, HANDLE *lpHandles, BOOL fWaitAll, DWORD dwMilliseconds),DWORD;
declare cdecl import, OutputDebugStringA(string str);


declare IMPORT,midiOutOpen(hMidi as UINT ByRef,uDeviceID as UINT,dwCallback as UINT,dwCBInstance as UINT,dwFlags as UINT),UINT;
declare IMPORT,midiOutSetVolume(hMidiOut as UINT,vol as INT),int;
declare IMPORT,midiOutClose(hMidiOut as UINT),int;
declare IMPORT,midiOutShortMsg(hMidiOut as UINT,dwMsg as UINT),int;
DECLARE IMPORT,midiStreamClose(hStream as UINT),INT;
DECLARE IMPORT,midiStreamOpen(lphStream as UINT ByRef,puDeviceID as UINT ByRef,cMidi as UINT,dwCallback as UINT,dwInstance as UINT,fdwOpen as UINT ),INT ;
DECLARE IMPORT,midiStreamOut(hStream as UINT,lpMidiHdr as POINTER,cbMidiHdr as UINT),INT;
DECLARE IMPORT,midiStreamRestart(hStream as UINT),INT;
DECLARE IMPORT,midiStreamStop(hStream as UINT),INT;
DECLARE IMPORT,midiStreamProperty(hStream as UINT,lpPropData as POINTER,dwProperty as UINT),INT;
DECLARE IMPORT,midiOutPrepareHeader(hmo as UINT,lpMidiOutHdr as POINTER,cbMidiOutHdr as UINT),INT;
DECLARE IMPORT,midiOutUnprepareHeader(hmo as UINT,lpMidiOutHdr as POINTER,cbMidiOutHdr as UINT),INT  ;
DECLARE IMPORT,CreateEventA(lpEventAttributes as POINTER,bManualReset as INT,bInitialState as INT,lpName as POINTER),UINT;
DECLARE IMPORT,CloseHandle(handle as UINT),INT;
DECLARE IMPORT,ResetEvent(hEvent as UINT),INT;
DECLARE IMPORT,SetEvent(hEvent as UINT),INT;
DECLARE IMPORT,WaitForSingleObject(handle as UINT,dwMilliseconds as UINT),INT;
DECLARE IMPORT,CreateThread(lpThreadAttributes as POINTER,dwStackSize as UINT,lpStartAddress as UINT,lpParameter as POINTER,dwCreationFlags as UINT,lpThreadId as UINT ByRef),UINT ;
DECLARE IMPORT,ResumeThread(hThread as UINT),INT;
CONST MM_MOM_CLOSE = 0x3C8;
CONST MM_MOM_DONE = 0x3C9;
CONST MM_MOM_OPEN = 0x3C7;
CONST MM_MOM_POSITIONCB = 0x3CA;
CONST MIDIPROP_GET = 0x40000000;
CONST MIDIPROP_SET = 0x80000000;
CONST MIDIPROP_TEMPO = 0x2;
CONST MIDIPROP_TIMEDIV = 0x1;
CONST CALLBACK_EVENT = 0x50000;
CONST CALLBACK_FUNCTION = 0x30000;
CONST INFINITE = 0xFFFFFFFF;
CONST MOM_POSITIONCB = MM_MOM_POSITIONCB;
CONST MOM_OPEN = MM_MOM_OPEN;
CONST MOM_DONE = MM_MOM_DONE;
CONST MOM_CLOSE = MM_MOM_CLOSE;
CONST TIME_BYTES = 0x4;
CONST TIME_MIDI = 0x10;
CONST TIME_MS = 0x1;
CONST TIME_SAMPLES = 0x2;
CONST TIME_SMPTE = 0x8;
CONST TIME_TICKS = 0x20;
CONST CALLBACK_NULL = 0x0;
CONST MEVT_F_CALLBACK = 0x40000000;
CONST MEVT_F_LONG = 0x80000000;
CONST MEVT_F_SHORT = 0;
CONST MEVT_TEMPO = 0x1;

CONST MLTYPENOTE =0x01;
CONST MLTYPEREST =0x02;
CONST MLTYPEPATCH =0x03;
CONST MLTYPETEMPO = 0x04;
CONST NOTE_ON = 0x90;
CONST NOTE_OFF = 0x80;
CONST PATCH_CHANGE = 0xC0 ;
CONST CONTROLLER_CHANGE = 0xB0;

CONST CREATE_SUSPENDED = 0x4;

class general
{
pointer pTemp,pReturn;
int nTemp;

struct ObjThread
{
uint tThread;
uint stopEvent;
}

declare general();
declare _general();
declare diff2time(int p1, int p2),int;
declare *ThreadProc(ObjThread *param);
declare TestThread(),uint;
declare TerThread(uint p0),int;
}


I have switched the pointers so they are global to the class.
I also made the structure global to the class.
When the class is initialized, it sets the default for nTemp and pTemp.

It looks like calling the ThreadProc method is where it breaks.
I have added hEvent to the RunProc, which really does nothing at this moment, and didn't exist before when I had all those problems as it is.

Ionic Wind Support Team

Sorry I only briefly looked at your code.  Closing a handle does not stop a thread.  A thread has to return from its point of execution to end or has to be suspended by your code.

If you look at my playmidistr example I use an event to signal the thread that it should end, and then wait for that thread to end before continuing.


global SUB STOPMIDISTR(MIDITHREAD *pStream)
{
IF pStream
{
IF pStream->hThread
{
SetEvent(pStream->stopEvent);
WaitForSingleObject(pStream->hThread,INFINITE);
CloseHandle(pStream->hThread);
pStream->hThread = NULL;
}
DELETE pStream;
}
}


The thread code itself watches for the 'stopEvent' variable in a while loop.  That loop also monitors the midi stream for playback.

Ionic Wind Support Team

sapero

the first bug i have found: WaitForSingleObject, WaitForMultipleObjects and OutputDebugStringA are NOT cdecl ;)

J B Wood (Zumwalt)

You have got to be kidding me.
The cdecl was blowing me up.
Oh my freaking... insert choice word here.

With that simple adjustment, and not adding a watchdog yet in the code, this was the end result:

Starting debug session...
Loading DLL: ntdll.dll
Loading DLL: C:\WINDOWS\system32\kernel32.dll
Loading DLL: C:\WINDOWS\system32\USER32.DLL
Loading DLL: C:\WINDOWS\system32\GDI32.dll
Loading DLL: C:\WINDOWS\system32\DINPUT.DLL
Loading DLL: C:\WINDOWS\system32\msvcrt.dll
Loading DLL: C:\WINDOWS\system32\ADVAPI32.dll
Loading DLL: C:\WINDOWS\system32\RPCRT4.dll
Loading DLL: C:\WINDOWS\system32\WINMM.dll
Loading DLL: C:\WINDOWS\system32\DX3D9R.DLL
Loading DLL: C:\WINDOWS\system32\d3d9.dll
Loading DLL: C:\WINDOWS\system32\d3d8thk.dll
Loading DLL: C:\WINDOWS\system32\VERSION.dll
Loading DLL: C:\WINDOWS\system32\MSVCP60.dll
Loading DLL: C:\WINDOWS\system32\CRTDLL.DLL
Loading DLL: C:\WINDOWS\system32\IMM32.DLL
Loading DLL: C:\WINDOWS\system32\uxtheme.dll
Loading DLL: C:\WINDOWS\system32\MSCTF.dll
Loading DLL: C:\WINDOWS\system32\SynTPFcs.dll
Loading DLL: C:\WINDOWS\system32\msctfime.ime
Loading DLL: C:\WINDOWS\system32\ole32.dll
Loading DLL: C:\WINDOWS\system32\usp10.dll
Loading DLL: C:\WINDOWS\system32\HID.DLL
Loading DLL: C:\WINDOWS\system32\SETUPAPI.DLL
Loading DLL: C:\WINDOWS\system32\WINTRUST.dll
Loading DLL: C:\WINDOWS\system32\CRYPT32.dll
Loading DLL: C:\WINDOWS\system32\MSASN1.dll
Loading DLL: C:\WINDOWS\system32\IMAGEHLP.dll
Last Error: 0
Last Error: 0
Last Error: 0
Last Error: 0
Thread is Closed!
Thread Result: 1334744
Last Error in ThreadProc: 0
Last Error in RunProc: 0
Thread is Running!
The thread 0xACC exited with code: 0
The thread 0x13F8 exited with code: 0
The program 'C:\Program Files\Aurora\projects\Aurora3d\Aurora3D.exe' exited with code: 0

J B Wood (Zumwalt)

Now to work on the watchdog and thread terminator so it works properly.
Then for some real testing and see if I can make another stupid mistake :)

Ionic Wind Support Team

lol.  Nice spot Sapero ;) 

When using the Windows API remember that the only funcitons that are declared cdecl are those that use a variable number of parameters.  wsprintf comes to mind, think there is one or two others, but not many.

Ionic Wind Support Team

J B Wood (Zumwalt)

Learn something new every day, and generally forget it the next.
New issue that has me stumped:


Starting debug session...
Loading DLL: ntdll.dll
Loading DLL: C:\WINDOWS\system32\kernel32.dll
Loading DLL: C:\WINDOWS\system32\USER32.DLL
Loading DLL: C:\WINDOWS\system32\GDI32.dll
Loading DLL: C:\WINDOWS\system32\DINPUT.DLL
Loading DLL: C:\WINDOWS\system32\msvcrt.dll
Loading DLL: C:\WINDOWS\system32\ADVAPI32.dll
Loading DLL: C:\WINDOWS\system32\RPCRT4.dll
Loading DLL: C:\WINDOWS\system32\WINMM.dll
Loading DLL: C:\WINDOWS\system32\DX3D9R.DLL
Loading DLL: C:\WINDOWS\system32\d3d9.dll
Loading DLL: C:\WINDOWS\system32\d3d8thk.dll
Loading DLL: C:\WINDOWS\system32\VERSION.dll
Loading DLL: C:\WINDOWS\system32\MSVCP60.dll
Loading DLL: C:\WINDOWS\system32\CRTDLL.DLL
Loading DLL: C:\WINDOWS\system32\IMM32.DLL
Loading DLL: C:\WINDOWS\system32\uxtheme.dll
Loading DLL: C:\WINDOWS\system32\MSCTF.dll
Loading DLL: C:\WINDOWS\system32\SynTPFcs.dll
Loading DLL: C:\WINDOWS\system32\msctfime.ime
Loading DLL: C:\WINDOWS\system32\ole32.dll
Loading DLL: C:\WINDOWS\system32\usp10.dll
Loading DLL: C:\WINDOWS\system32\HID.DLL
Loading DLL: C:\WINDOWS\system32\SETUPAPI.DLL
Loading DLL: C:\WINDOWS\system32\WINTRUST.dll
Loading DLL: C:\WINDOWS\system32\CRYPT32.dll
Loading DLL: C:\WINDOWS\system32\MSASN1.dll
Loading DLL: C:\WINDOWS\system32\IMAGEHLP.dll
Last Error in ThreadProc: 0
Last Error in RunProc: 0
Thread is Running!
The thread 0x11DC exited with code: 0
Thread is Closed!
HEAP[Aurora3D.exe]:
Invalid Address specified to RtlFreeHeap( 00140000, 00145DD8 )

User breakpoint encountered: Address 0x7C901230
The thread 0x920 exited with code: 1
The program 'C:\Program Files\Aurora\projects\Aurora3d\Aurora3D.exe' exited with code: 1



This happens ONLY after I terminate from my game loop and go into my terminate code, never happened before, and I am already done with the threading stuff.
Any ideas?

J B Wood (Zumwalt)

Nevermind... another idiotic mistake.


general :: _general()
{
DELETE pTemp;
}


I was trying to destroy something that was already destroyed.
Duh.

J B Wood (Zumwalt)

By the way, thanks both Paul and Sapero.
I now have the 'core' to my enemy spawner ready.
I will start tonight on building the enemy structure.

This core can also now be used for ammo, and anything else that needs a short life.
Going to mass spawn and have them terminate on 10 second intervals to see how many I can get loaded in 4 gigs of ram.