SDL Program not responding(is handling events)

Pages: 12
I'm doing this SDL program, and I wrote a lot of it on windows, where it worked fine. Then I had to program on linux for some time, and it worked there too. Now that I've returned to windows the program does not respond. The event handling code is the same and hasn't changed but here it is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
eventThread = SDL_CreateThread(t_eventLoop, NULL);

...

int t_eventLoop(void * d)
{
	SDL_Event event;
	while (!quit)
	{
		while (SDL_PollEvent(&event))
			handleEvent(&event);
	}
	return 0;
}

...

void handleEvent(SDL_Event * event)
{
	...
	switch (event->type)
	{
	case SDL_QUIT:
		quit = true;
		break;
	case SDL_KEYDOWN:
		...
		break;
	case SDL_KEYUP:
		...
		break;
	}
}

I've tried to cut out the new parts of the code, but with no luck.
I hope you guys have an idea of what could be wrong.
Looks like you have no synchronization between threads.
Well what kind of synchronization is needed when you just have an event thread and a graphics thread(the logic is in the main loop not a thread)?
Last edited on
You need to make sure that one thread is not manipulating a variable while other threads are 'using' it. Some SDL functions might not be thread safe.
http://www.libsdl.org/cgi/docwiki.cgi/FAQ_Function_calls_from_multiple_threads
Last edited on
Well the logic does not interface with SDL, and the graphics threads are locked with semaphores. And as I said it all worked on linux, it's a windows specific problem.
Ok, I tested it on the different operating systems, and the difference is that on Windows it does only respond to 4 - 6 events and then it stops responding to events and therefore Windows renders the program "Not responding". But it works on linux.
Only the main thread should call SDL_PollEvent() and related functions.
I'll try that.
EDIT:
I went from:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main(int argc,char * argv[])
{
...
loop();
...
}

void loop()
{
...
eventThread = SDL_CreateThread(t_eventLoop,NULL);
...
}

int t_eventLoop(void * d)
{
	SDL_Event event;
	while (!quit)
	{
		while (SDL_PollEvent(&event))
			handleEvent(&event);
		SDL_Delay(1);
		cout << "still here" << endl;
	}
	return 0;
}

to:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int main(int argc,char * argv[])
{
...
loop();
...
}

void loop()
{
...
        SDL_Event event;
	while (!quit)
	{
		while (SDL_PollEvent(&event))
			handleEvent(&event);
		SDL_Delay(1);
		cout << "still here" << endl;
	}
...
}

But no difference, it's still not responding.
Last edited on
I'll need to see the entire program.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
 NOTES:
 	 Anything that has to do with the terminal can be 100% disabled, but there is no difference.
 */


#include "headers/subnet.hpp"
#include "headers/netcode.hpp"
#include "headers/netcrypt.hpp"
#include "headers/terminal.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
using namespace std;

SDL_Surface * stdscr;
bool quit = false;
vector<InputListener*> * listeners;
SDL_Thread * eventThread;
SDL_Thread * inputThread;

InputListener::~InputListener()
{
	return;
}

void InputListener::keyDown(SDL_keysym s)
{
	return;
}
void InputListener::keyUp(SDL_keysym s)
{
	return;
}
void InputListener::keyAction(bool b, SDL_keysym s)
{
	return;
}

void handleEvent(SDL_Event * event)
{
	vector<InputListener *>::iterator it;
	switch (event->type)
	{
	case SDL_QUIT:
		stdterm->print("bye!");
		quit = true;
		break;
	case SDL_KEYDOWN:
		for (it = listeners->begin(); it < listeners->end(); it++)
		{

			if ((*it)->active)
			{
				if ((*it)->mono) (*it)->keyAction(true, event->key.keysym);
				else (*it)->keyDown(event->key.keysym);
			}
		}
		break;
	case SDL_KEYUP:
		for (it = listeners->begin(); it < listeners->end(); it++)
		{

			if ((*it)->active)
			{
				if ((*it)->mono) (*it)->keyAction(false, event->key.keysym);
				else (*it)->keyUp(event->key.keysym);
			}
		}
		break;
	case SDL_VIDEOEXPOSE:
		SDL_Flip(stdscr);
		break;
	}
}

void handleInput(const char * s)
{
	//TODO:
	stdterm->print("");
	if(strcmp(s,"tutorial")==0)
	{
		stdterm->print("You need a tutorial? Ha! you noob!");
	}else
	{
		stdterm->print("Unknown command!");
	}
}

int t_inputLoop(void * d)
{
	listeners->push_back(stdterm);
	stdterm->print("Welcome to SubNet! type 'tutorial' or 'commands' for help.");
	while (!quit)
	{
		handleInput(stdterm->getstr());
		SDL_Delay(1);
	}
	return 0;
}

//int t_eventLoop(void * d)
//{
//	SDL_Event event;
//	cout.flush();
//	while (!quit)
//	{
//		while (SDL_PollEvent(&event))
//			handleEvent(&event);
//		SDL_Delay(1);
//		cout << "still here" << endl;
//	}
//	return 0;
//}

void loop()
{
	SDL_Event event;
	//eventThread = SDL_CreateThread(t_eventLoop, NULL);
	inputThread = SDL_CreateThread(t_inputLoop, NULL);//Can be commented out no difference!
	while (!quit)
	{
		while (SDL_PollEvent(&event))
			handleEvent(&event);
		cout.flush();
		SDL_Flip(stdscr);
		SDL_Delay(1);
	}
}

void quitAll()
{
	quit_terminal();
	quit_net();
	SDL_Quit();
}

int main(int argc, char *argv[])
{
	if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
	{
		cout << "Something went wrong in SDL_Init\n";
	}
	atexit(quitAll);
	cout << "Starting up SubNet\n";
	listeners = new vector<InputListener*>;
	try
	{
		init_net();
		cout << "Netcode init\n";
		cout << "Terminal init\n";
		SDL_WM_SetCaption("SubNet", NULL);
		stdscr = SDL_SetVideoMode(TERM_WIDTH * 8, TERM_HEIGHT * 8, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
		init_terminal();
		loop();
	} catch (const SubNetException& e)
	{
		cout << e.what() << endl;
	}

	return 0;
}
Does the program still consume CPU while it doesn't respond? If so, can you run it through the debugger and pause it to see where the control flow is?
Well you can't see if it consumes CPU since it is rendered as using 0% CPU doesn't matter what. But a cursor blink thread stops working when Windows renders it "Not responding" and greys out.
since it is rendered as using 0% CPU


That means it is not consuming CPU.

But a cursor blink thread stops working when Windows renders it "Not responding" and greys out.


Sounds like your threads are deadlocking. Probably what's happening is thread A is trying to lock a mutex that is owned by thread B... while thread B is waiting to lock a mutex owned by thread A -- so they both deadlock because neither mutex is freed.


EDIT:

That said... multithreading really adds tons of complexity to code (especially in games, where logic is mostly linear). Unless you have a really good reason to have multiple threads, you probably should just keep everything in a single thread.
Last edited on
There is no mutexes in my code, only 1 semaphore that locks down the rendering code. The reason why Windows "renders" it as using 0% is because it's using less than 1%( 0.XX% ) and is just displayed as 0% CPU.

Multithreading is needed if command input, background processes, networking , graphics and event handling should be possible to have at the same time.
There is no mutexes in my code, only 1 semaphore that locks down the rendering code.
Mutexes or semaphores. Both can cause deadlocks. It's hard to know if something is wrong because we can't see all the code. Where is the semaphore you talk about? Is the headers in the headers directory you own code or from a library?

The reason why Windows "renders" it as using 0% is because it's using less than 1%( 0.XX% ) and is just displayed as 0% CPU.
Remove the calls to SDL_Delay and see what you get.
The one and only semaphore:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void Terminal::drawChar(char c, short x, short y)
{
	SDL_SemWait(drawSema);
	change = true;
	SDL_Rect r;
	SDL_Rect ar;
	ar.w = 8;
	ar.h = 8;
	ar.x = c * 8;
	ar.y = 0;
	r.x = x * 8;
	r.y = y * 8;
	//if (SDL_MUSTLOCK(stdfont)) SDL_UnlockSurface(stdfont);
	//if (SDL_MUSTLOCK(stdscr)) SDL_UnlockSurface(stdscr);
	if (SDL_BlitSurface(stdfont, &ar, stdscr, &r) < 0)
	{
		std::cout << "BLIT FAILED FROM STDFONT: " << SDL_GetError() << "\n";
	}
	SDL_SemPost(drawSema);
}

And about the headers?: http://imageshack.us/a/img339/7844/sourcesnheaders.png

If I remove the SDL_Delay(1);s I still get 0% CPU usage before it Windows renders it not responding.
If this is the only function the semaphore is used it doesn't really do anything.

About the headers. If it's your own code there could be a lot of things going wrong and if we can't see it we can't know.
Well the headers are class mostly class headers or modules, and all modules ( Except subnet.hpp/cpp) can be unplugged and we still get no difference to the "not responding" problem. The drawChar() is called from multiple threads, therefore it has a semaphore.
Create a minimal example that can be compiled and that have the "not responding" problem. Remove as much irrelevant code as possible. Post the code here and we can have a look at it.
Here's a possible source of problems I just noticed: you're calling SDL_Flip() in the main thread without any kind of locking, while other threads may be drawing to the screen at the same time.

Have you tried my suggestion of pausing the program in debugging to see where the control flow stalls?
Pages: 12