(Multi-) Threading

Discuss programming topics for the various GPL'd game engine sources.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: (Multi-) Threading

Post by Baker »

revelator wrote:atm the simplest ide i can give you if you want is sadly gcc based but pretty much as clean as the old msvc 6 IDE.
Something to keep in mind, Visual Studio has edit and continue. And I like being able to write new code during execution, so switching IDEs isn't something viable for me, since no compilers other than Microsoft's can perform this (and do it reliably, I recall some old version of Apple's gcc or maybe even the base gcc one had a buggy form of this once or even now). AFAIK not even LLVM can do this.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: (Multi-) Threading

Post by revelator »

gcc itself does not but the debugger gdb does to some degree and then the old apple compilers where it was called fix and continue :P.
its planned for clang i hear but its a long term solution due to the massive ammount of targets it supports so dont expect a full fledged solution anytime soon.
Productivity is a state of mind.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: (Multi-) Threading

Post by Baker »

Nothing useful to say except pthreads is awesome from everything I see.

It's very clean.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: (Multi-) Threading

Post by revelator »

easier to work with than windows threads also :) the winpthreads version is actually just a wrapper around the windows thread stuff.
Only reason the mingw64 people use it is that the g++ c++11 extentions and openmp needs pthreads, having gcc rely on another dll was just a bit much for me to swallow,
so i patched mingw64 with the patchset from TDM to allow linking it statically and be done with it.

but nice to know that it has other uses :)
Productivity is a state of mind.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: (Multi-) Threading

Post by Baker »

Spike wrote:pthreads everywhere! ... reap the benefit of choosing standards instead of implementations!
This -- So much easier!

I have everything all setup and tested against static libs (and dynamic libs)

Thanks revelator for those libraries, I've got everything fully setup and tested and life is going to be easy with pthreads!

And thanks to your help I have an entirely DLL free engine (*) that does everything I want and I can build it with CodeBlocks too!

I did have a LIBCURL dependency that ProQuake uses for http map download and a very recent Mark V had used for mod installation. But I killed that off a week ago by doing something Spike-like and jamming http capability directly into the client.

[Libcurl has a ridiculous zlib1.dll dependency (a 40 kb file, seriously? And zlib is has a bsd-like license too) when you compile statically.]
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: (Multi-) Threading

Post by Baker »

I did a test with a few items:
1) Create a queue of messages so threads can Con_Printf -- it doesn't happen immediately, they print when Host_Frame swings around.
2) Made something that touches every .bsp in the maps folder on gamedir set/change to wake up disk (*)

[prevents any delays in my engine if the map menu is used and those files are touched for the first time. I have it open the .bsp files and find the name of the map and only do a few per frame but if those files are "asleep" the sound stutters like crazy.]

pthreads is fun after you get it setup!

Look foward to combining it with networking to have a server background transfer files to the client.

Code: Select all

clist_t *con_queue_prints;
pthread_mutex_t queue_printf_mutex = PTHREAD_MUTEX_INITIALIZER;

void Con_Queue_Printf (const char *fmt, ...)
{
	VA_EXPAND (text, SYSTEM_STRING_SIZE_1024, fmt)
	
	// Enure exclusive access to the list.
	pthread_mutex_lock (&queue_printf_mutex);   
	List_Add_Unsorted (&con_queue_prints, text);
	pthread_mutex_unlock (&queue_printf_mutex);
}

void Con_Queue_PrintRun (const char *url)
{
	clist_t *cur;
	// Enure exclusive access to the list.	
	pthread_mutex_lock (&queue_printf_mutex);  

	for (cur = con_queue_prints ; cur; cur = cur->next)
		Con_SafePrintf (cur->name);  // Don't tie up time -- SafePrint doesn't SCR_Update like Con_Printf
	
	List_Free (&con_queue_prints);

	pthread_mutex_unlock (&queue_printf_mutex);
}

void File_Read_Touch (const char *path_to_file)
{
	FILE *f = fopen (path_to_file, "rb"); // Don't use FS_open_read --- the register isn't thread safe
	if (f)
	{
		char buf[4];
		fread (buf, 1, sizeof(buf), f);
		fclose (f); // Don't use FS_close --- the register isn't thread safe
	}
}

clist_t *file_read_list_urls; // MAX_QPATH * num
pthread_t read_list_thread;
volatile cbool read_list_cancel;

   
void *ReadList_Reader (void *pclist)
{
	clist_t *cur = NULL;
	int	count;

	Con_Queue_Printf ("Thread started\n"); // Thread-safe queuing of messages, blocking.

	// We don't need to lock anything here, we have exclusive access to the list by design
	for (cur = file_read_list_urls, count = 0; cur && !read_list_cancel; cur = cur->next, count ++)
	{
		File_Read_Touch (cur->name);
		// Con_Queue_Printf ("Touched %04i %s\n", count, cur->name); // Thread-safe, blocking.
	}

	if (read_list_cancel)
		Con_Queue_Printf ("Thread received stop signal\n", count, cur->name); // Thread-safe, blocking.

	List_Free (&file_read_list_urls);

	Con_Queue_Printf ("Thread ended\n"); // Thread-safe, blocking.
	pthread_exit (NULL); // This is optional unless you want to return something for pthread_join to read.
	return NULL;
}

void ReadList_Ensure_Shutdown (void)
{
	// Make sure our list reading thread isn't running.
	read_list_cancel = true; // Tell it to wrap up
	pthread_join (read_list_thread, NULL);
}

   
void ReadList_NewGame (void)
{	
	pthread_attr_t attr;
	searchpath_t *search;

	// Make sure our list reading thread isn't running.
	ReadList_Ensure_Shutdown(); // Tells thread to stop what it is doing and cleanly exit

	// We have to construct the list here because File_List_Alloc isn't thread safe at all (uses va)
	// Free the list first
	if (file_read_list_urls)
		List_Free (&file_read_list_urls);

	// Get the last gamedir
	for (search = com_searchpaths; search; search = search->next)
		if (search->filename[0]) //directory
		{
			clist_t *new_files = NULL;
			// Ok, this will return healthbox bsps and such, it's ok to touch those.
			char tmp_path[MAX_OSPATH];
			c_snprintf (tmp_path, "%s/maps", search->filename);
			new_files = File_List_Alloc (tmp_path, ".bsp");

			List_Concat_Unsorted (&file_read_list_urls, new_files);
			//break;
		}

	read_list_cancel = false;
		
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
	pthread_create(&read_list_thread, &attr, ReadList_Reader, NULL);
}
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: (Multi-) Threading

Post by revelator »

:) nice.

i guess thread sleep would be something nasty to avoid then ;) atleast from examples i seen.
Productivity is a state of mind.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: (Multi-) Threading

Post by Baker »

revelator wrote::) nice.

i guess thread sleep would be something nasty to avoid then ;) atleast from examples i seen.
Explain that if you don't mind.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: (Multi-) Threading

Post by revelator »

Just seems commented in several sources that thread functions behave badly if they are put on hold,
something about them going out of sync so that it takes a while for things to catch up when resuming.

From the top of my head last time i seen this was in the cygwin core of all places ...
Productivity is a state of mind.
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: (Multi-) Threading

Post by revelator »

Ok dug up something about it.

It seems when using thread sleep it will block execution even in the main thread so things can pretty easily fuck up,
so if you dont want it to totally grind everything to a halt a non blocking sleep function might be the better alternative.

Ill see if i can find some examples.
Productivity is a state of mind.
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: (Multi-) Threading

Post by revelator »

Hum hmm.

Code: Select all

#include <windows.h>

static void func(void)
{
  HANDLE hTimer = NULL;
  LARGE_INTEGER liDueTime;

  liDueTime.QuadPart = -5000000LL;    // 0.5 seconds
  //liDueTime.QuadPart = -20000000LL;   // 2 seconds
  //liDueTime.QuadPart = -100000000LL;  // 10 seconds


  hTimer = CreateWaitableTimer(NULL, TRUE, NULL);


  SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0);

  while (WaitForSingleObject(hTimer, 0) == WAIT_TIMEOUT)
  {
    do stuff
  }
}
atleast for windows this works fine, not sure if of any use in your project.

Ill see if i can find something related to pthreads.
Productivity is a state of mind.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: (Multi-) Threading

Post by Baker »

revelator wrote:Just seems commented in several sources that thread functions behave badly if they are put on hold
I'm not sure where you mean. Is it where I have a mutex guarding the queued console prints lists?

Or how I have a shutdown that does pthread_join before starting threads?

That's to handle a possible oddball scenario of someone having massive amounts of maps or demos and rapidly switching the gamedir. It tells the thread to stop --- which it does very rapidly, I had the thread do a infinite loop a few times to make sure.

Your way more experienced than I in threads :D I just wanna know where so I can check.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: (Multi-) Threading

Post by revelator »

mostly in windows threads which are not a lot of fun to toy with xD

in pthreads you use pthread_sigmask to set wait flags :) but im still reading into it myself, i do hope to have something useable soon though.
Productivity is a state of mind.
jitspoe
Posts: 217
Joined: Mon Jan 17, 2005 5:27 am

Re: (Multi-) Threading

Post by jitspoe »

Throwing in a couple cents from what I've learned with multithreading:

1) Don't bother unless there's an obvious benefit. Figuring out multithreading bugs is a whole new level of nightmare. Obvious benefits are things like: responsive UI while establishing HTTP connections or loading files. Squeezing another 10fps of performance when you're already getting 500fps... not so much. Regarding 'net connections, I've found it's better to just use non-blocking UDP sockets when possible. Much less of a headache than multithreading.

2) Windows threading functions really aren't that bad. I did the pthread stuff on windows for a bit, and later just started #defining some macros so I could be cross-platform compatible without the headache of managing yet another library.

Code: Select all

#ifdef WIN32
#include <winsock.h>
static DWORD threadid;
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>
#define CRITICAL_SECTION pthread_mutex_t
#define EnterCriticalSection(a) pthread_mutex_lock(a)
#define LeaveCriticalSection(a) pthread_mutex_unlock(a)
#define InitializeCriticalSection(a) pthread_mutex_init(a, NULL)
#define HANDLE pthread_t
#define LPTHREAD_START_ROUTINE void*
//#define ResumeThread(a) pthread_cond_signal(&cond)
//#define SuspendThread(a) pthread_cond_wait(&cond, &condmutex), pthread_mutex_unlock(&condmutex)
#define DeleteCriticalSection(a) pthread_mutex_destroy(a)
#define closesocket(a) close(a)
//pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//pthread_mutex_t condmutex = PTHREAD_MUTEX_INITIALIZER;
typedef uint32_t DWORD;
#define Sleep(a) usleep((a) * 1000)
#endif
Windows actually handles some things better. For example, you can safely enter a critical section on the same thread if you're already in that thread. With mutexes... not so much. Immediate deadlock. Which brings me to:

3) Recursive functions and mutexes don't mix well. Ex: FunctionA() -> MutexA -> FunctionA() -> MutexA LOCKED.

4) Deadlocks and other issues show up surprisingly fast. I'm not saying to rely on that, but I found it surprising that issues I wouldn't expect to show up more than 1 in a thousand runs due to timing happened almost immediately. Of course, there are always the less obvious ones that do only show up 1 in a thousand runs...

5) This may just be a Windows thing, but threading won't save you from slow drives. If you access something on a drive in one thread, and it has to spin up or whatever, if any other thread accesses something from ANY drive, it will stall. Everything will stall.

6) As jdolan mentioned, if you're dealing with shared data you will most likely need to duplicate it, and make sure you have a safe location where you can copy the data without any of the threads trying to access it.
revelator
Posts: 2621
Joined: Thu Jan 24, 2008 12:04 pm
Location: inside tha debugger

Re: (Multi-) Threading

Post by revelator »

Good stuff in both archs :) and aye dont just use threading if something does not perform to well sometimes its just better to optimize your code a bit more for single threading.
IN the end it depends on what you want to do :) multithreading works well if you have several performance intensive code targets, but can be a pain in the arse to sync up.
Pthreads are easy but its not always a good thing, still its nice to have have but more experience in how things work is allways better.
Productivity is a state of mind.
Post Reply