Skip to main content
gamedev.net
🔒 Locked

Multi Threading?

Started by GetWindowRect Sep 10, 2005 at 8:43 PM 13 replies 6.6k views
Original Post
GetWindowRect
GetWindowRect
I am not quite sure what I have done wrong, but I have a window wrapper class to create windows. I create a new window class in a button click which then freezes both window's. I have used the same code in other programs and I have not ran into this problem. I am thinking that the message loop freezes the first window's message loop because the new window starts a message loop in the WM_COMMAND message. I am not quite sure, if that is the case, why it only does it in this application and not others, but it makes sense. Anyway, I tried to make a thread to call the new window creation and I am getting the following error: error C2664: 'CreateThread' : cannot convert parameter 3 from 'int (LPVOID)' to 'LPTHREAD_START_ROUTINE'

//Client is my class that inherits from the Window class.
		DWORD WINAPI ThreadProc(LPVOID lpParameter)
		{
			//LPTHREAD_START_ROUTINE
			//Open the Client form in a new thread.
			frmClient = new Client("wInternetClient", "Internet Test - Client");
			frmClient->Position(225, 225); 
			frmClient->Size(220, 100);
			frmClient->Style = WS_BORDER | WS_CAPTION;
			frmClient->StyleEx = WS_EX_STATICEDGE;
			frmClient->BackColor(212, 208, 200);
			frmClient->Show();
		}


//In the WM_COMMAND for the connect button I have the following line to create the thread
hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, 999);

I am not sure if I am doing something wrong somewhere, but if anyone can help, or point me in the right direction, I would appreciate it greatly. If more code is required I would be happy to post more.
GetWindowRect
GetWindowRect
Well, for the issue this all started with, I was creating a timer with SetTimer() right before creating the window. When I comment it out, everything runs fine. If I put the form in front of the SetTimer() function call does not get called until after I close the client form. I think threading is about the only way I can go about fixing this, but who knows I am wrong a lot. I still cannot figure out why I cannot run the thread. On MSDN they create a ThreadProc function with the same return value and parameter, and call CreateThread in the same manner as I am. However, I get the error as posted above. Thanks in advance.
Liam M
Liam M
Try this instead:

DWORD WINAPI ThreadProc(LPVOID lpParameter){	//LPTHREAD_START_ROUTINE	//Open the Client form in a new thread.	frmClient = new Client("wInternetClient", "Internet Test - Client");	frmClient->Position(225, 225); 	frmClient->Size(220, 100);	frmClient->Style = WS_BORDER | WS_CAPTION;	frmClient->StyleEx = WS_EX_STATICEDGE;	frmClient->BackColor(212, 208, 200);	frmClient->Show();return ((DWORD)lpParameter);		}


That might work.
GetWindowRect
GetWindowRect
Thank you for the reply, I was too caught up in the error to remember to put the return value. However, it did not fix the problem, I am still getting:
error C2664: 'CreateThread' : cannot convert parameter 3 from 'DWORD (LPVOID)' to 'LPTHREAD_START_ROUTINE'

I think it was originally int(LPVOID) now it is back to DWORD. I appreciate the thought though, thanks again.
GetWindowRect
GetWindowRect
I was reading up a little more on threads and I saw that CreateThread and CloseHandle can have problems and cause memory leaks. The recommended alternative was _beginthreadex(). However, in order to use it, you have to include . I include the file, yet now I get the error:
error C3861: '_beginthreadex': identifier not found, even with argument-dependent lookup

I cannot find anywhere that I need to include a .lib file or anything, only the header. I think I will keep looking into this version rather than the alternate CreateThread method.
Nychold
Nychold
I've never had any problems with CreateThread. Just type cast it:

CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadProc,NULL,0,&someInt);


And I read that "small memory leak advisory" they talk about in the Win32 API, but I'm using two threads, both of which call fread from the standard C libraries, and no memory leaks. Not even small ones. ;)

Just don't call ExitThread. Let the thread run out, or put a boolean to tell the thread to "exit" by passing it through the parameter. Either way, never order the thread to exit.
GetWindowRect
GetWindowRect
Thank you very much for your reply Nychold: I did try to cast the function to LPTHREAD_START_ROUTINE, it gave me an error telling me I could not convert the function to it.

error C2440: 'type cast' : cannot convert from 'overloaded-function' to 'LPTHREAD_START_ROUTINE'

Thank you for the thought though.
Nychold
Nychold
After looking over my code, pull that WINAPI out of there, and it should work fine.

Errr, wait a minute. Are you overloading the identifier "ThreadProc"? If so, I would say don't do it. It won't know which address to pass.
GetWindowRect
GetWindowRect
I don't think I am overloading it, and if I am, I am not doing it on purpose. Could it be thinking that I am because it is in a class? (probably dumb question).

Is there a ThreadProc function already created or something? Sorry for the silly questions, I am just pretty confused.
Nychold
Nychold
Yep, that'll do it. See, every call from a class has a "hidden" parameter in it, which carries "this" information. That's how C++ knows where it is. The only way to get around this is to make it static, and pass as a parameter your class. Here's (one of) mine:

    //...inside TAudioObject            hLoad=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)threadLoad,                           this,0,&threadID);    //...    static DWORD threadLoad(void *param)    {      TAudioObject *obj=(TAudioObject *)param;      // Thread must load 1 buffer, set the ready state      // and continue to load the other buffers with a      // short sleep state (50 milliseconds) between loads      alSourcei(obj->sourceID,AL_LOOPING,AL_FALSE);      for (int i=0;i<BUFFER_COUNT;i++)      {        switch (obj->type)        {          case AUDIO_WAV:            obj->StreamWAV(obj->bufferID);            break;          case AUDIO_OGG_VORBIS:            obj->StreamOGG(obj->bufferID);            break;        }        alSourceQueueBuffers(obj->sourceID,1,&obj->bufferID);        obj->ready=true;        SleepEx(100,true);      }      obj->hLoad=NULL;      obj->threadID=0;      return 0;    };


And no, it's not silly. I've been in a similar situation before numerous times. ;)
GetWindowRect
GetWindowRect
Thank you very much for helping me out as much as you have. I changed it to static, and now it is not giving me the errors.

I do have another question for you however. I am passing 999 as the last parameter to the CreateThread function which I am sure isn't the best thing. I noticed in yours you pass &threadID. What exactly is this used for?

Thank you again, I really appreciate your patience and help.
Nychold
Nychold
The return value from the thread function. At least, I think that's what it's for. I dunno, I've never really used it. ;) Even if you don't need it, you need to have a place for it.

EDIT: According to Schildt's Windows 95 Programming in C/C++, it's a unique identifier for the thread. Which to me, seems silly because CreateThread already returns a more useful unique ID...the HANDLE. Oh well. Like I said, I've never used it.
GetWindowRect
GetWindowRect
Yeah, you are correct. I was getting errors with my 999 idea. It is actually working now (to a degree). The new form is created, but now the other form recieves no messages. It doesn't paint or anything, and even after the new form is closed it stays "frozen". But that has nothing to do with CreateThread, I am probably not using CloseHandle() in the right place, or something. I will look into it.

Thanks again, this is starting to make a little sense.
GetWindowRect
GetWindowRect
Anonymous:
What I am "trying" to do is learn winsock, and I saw, what looks like, a decent tutorial on planetsourcecode.com. It shows how to create a server/listener and how to make something connect to it. I thought I would make a server form and a client form therefor (I guess/think) would want 2 message pumps? He mentioned that the accept function should be in a loop of some sort, but a while loop would freeze.

I figured I would put it in a timer instead. I figured out the reason for the "freezing" (to a degree). The problem is caused when I run the SetTimer function. For some reason when I create a timer on the server form, and open the client form, the server form freezes.

I refer to the window as a form because I am a VB nerd. sorry if it causes confusion.

I do know my design is not the best and there is a lot I could improve. I did not know only one message loop was needed in c++, I thought each form/window needed it's own to handle the messages, although as I am writing this it makes sense one message loop/pump/whatever could handle multiple windows because it has the HWND parameter which could handle multiple windows. I will look into using only one, it might fix some of my problems.

If you have any idea on why the SetTimer would cause this, or if it could be because of the multiple message pumps or what not, I would be glad to search for a better method. I have never been too fond of multithreading, it can turn into a huge jumbled mess. Thank you for the advice and ideas, hopefully I can figure out a better way to do this.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.