Jump to content

C++ Threads


Josh
 Share

Recommended Posts

I am not new to multithread programming, but I have never done it in C++. I want to create a thread to execute a function, and be able to tell when the thread is finished. The code should run on Windows and OSX. If it can run on Android and iOS, that's great, but I don't expect it to. Where can I find a simple example that shows how to do this?

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I have used this as a reference:

https://computing.llnl.gov/tutorials/pthreads/

 

MinGW comes with pthreads library, not sure about Visual Studio, but you can get it for it too, for example from here: http://sourceware.org/pthreads-win32/

 

Alternatively you could also use boost::thread class, which is also standard:

http://www.boost.org/doc/libs/1_47_0/doc/html/thread.html

Ryzen 9 RX 6800M ■ 16GB XF8 Windows 11 ■
Ultra ■ LE 2.53DWS 5.6  Reaper ■ C/C++ C# ■ Fortran 2008 ■ Story ■
■ Homepage: https://canardia.com ■

Link to comment
Share on other sites

I got started with win32 threads. I think I'd rather use my own class and just use macros to control the different behavior than to use something like Boost.

 

How can I check the status of a thread? I need to be able to tell if a thread is still running. See Thread::GetState():

 

Thread.h

#include "../le3.h"

#ifdef WINDOWS
namespace win32
{
#include <windows.h>
}
#endif

namespace le3
{
const int THREAD_RUNNING = 1;
const int THREAD_FINISHED = 0;
const int THREAD_PAUSED = 2;
const int THREAD_READY = 3;

class Thread
{
public:
	Object* result;

	#ifdef WINDOWS
	HANDLE id;
	#endif

	Thread();
	~Thread();

	virtual bool Resume();
	virtual bool Pause();
	virtual int GetState();
	virtual Object* GetResult();
};

Thread* CreateThread_(Object* EntryPoint(Object* o), Object* o=NULL);
}

 

Thread.cpp

#include "../le3.h"

namespace le3
{
Thread::Thread() : result(NULL)
{
	#ifdef WINDOWS
	id = 0;
	#endif
}

Thread::~Thread()
{
	#ifdef WINDOWS
	if (GetState()!=THREAD_FINISHED)
	{
		TerminateThread(id,0);
	}
	#endif
}

bool Thread::Pause()
{
	#ifdef WINDOWS
	if (SuspendThread(id)!=-1) return true;
	#endif
}

bool Thread::Resume()
{
	#ifdef WINDOWS
	if (ResumeThread(id)!=-1) return true;
	#endif
}

int Thread::GetState()
{
	#ifdef WINDOWS

	#endif
	return 0;
}

Object* Thread::GetResult()
{
	if (GetState()!=THREAD_FINISHED) return NULL;
	return result;
}

Thread* CreateThread_(Object* EntryPoint(Object* o),Object* o)
{
	Thread* thread = new Thread;

	#ifdef WINDOWS
	thread->id = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)EntryPoint,NULL,CREATE_SUSPENDED,NULL);
	if (!thread->id)
	{
		delete thread;
		return NULL;
	}
	#endif

	return thread;
}
}

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Eh, I got it figured out. Here's a nice little thread class if you need it:

#include "../le3.h"

#ifdef WINDOWS
namespace win32
{
#include <windows.h>
}
#endif

namespace le3
{
const int THREAD_RUNNING = 1;
const int THREAD_FINISHED = 0;
const int THREAD_PAUSED = 2;
const int THREAD_READY = 3;

class Thread
{
public:
	Object* result;

	#ifdef WINDOWS
	HANDLE id;
	int state;
	#endif

	Thread();
	~Thread();

	virtual void Wait();
	virtual bool Resume();
	virtual bool Pause();
	virtual int GetState();
	virtual Object* GetResult();
};

Thread* CreateThread_(Object* EntryPoint(Object* o), Object* o=NULL);
}

 

#include "../le3.h"

namespace le3
{
Thread::Thread() : result(NULL)
{
	#ifdef WINDOWS
	id = 0;
	state = THREAD_PAUSED;
	#endif
}

Thread::~Thread()
{
	#ifdef WINDOWS
	if (GetState()!=THREAD_FINISHED)
	{
		TerminateThread(id,0);
	}
	#endif
}

bool Thread::Pause()
{
	#ifdef WINDOWS
	if (SuspendThread(id)!=-1)
	{
		state = THREAD_PAUSED;
		return true;
	}
	else
	{
		return false;
	}
	#endif
}

bool Thread::Resume()
{
	#ifdef WINDOWS
	if (ResumeThread(id)!=-1)
	{
		state = THREAD_RUNNING;
		return true;
	}
	else
	{
		return false;
	}
	#endif
}

int Thread::GetState()
{
	#ifdef WINDOWS
	if (state==THREAD_RUNNING)
	{
		DWORD lpExitCode;
		if (GetExitCodeThread(id,&lpExitCode)==0)
		{
			//Function fails
			return THREAD_RUNNING;
		}
		else
		{
			if (lpExitCode==STILL_ACTIVE)
			{
				return THREAD_RUNNING;
			}
			else
			{
				return THREAD_FINISHED;
			}
		}
	}
	else
	{
		return state;
	}
	#endif
	return 0;
}

void Thread::Wait()
{
	while (GetState()!=THREAD_FINISHED)
	{
		//win32::sleep(1);
	}
}

Object* Thread::GetResult()
{
	if (GetState()!=THREAD_FINISHED) return NULL;
	return result;
}

Thread* CreateThread_(Object* EntryPoint(Object* o),Object* o)
{
	Thread* thread = new Thread;

	#ifdef WINDOWS
	thread->id = CreateThread(NULL,4,(LPTHREAD_START_ROUTINE)EntryPoint,o,CREATE_SUSPENDED,NULL);
	if (!thread->id)
	{
		delete thread;
		return NULL;
	}
	#endif

	return thread;
}
}

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Why would you use a completely different approach for Windows, when you can use pthreads on all platforms?

Anyway, with pthreads you can make thread states either with your own custom mutexed variables, or using the condition variables of threads:

http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html

Ryzen 9 RX 6800M ■ 16GB XF8 Windows 11 ■
Ultra ■ LE 2.53DWS 5.6  Reaper ■ C/C++ C# ■ Fortran 2008 ■ Story ■
■ Homepage: https://canardia.com ■

Link to comment
Share on other sites

Don't know if this is any help to anyone but I thought I'd just say that if one needs some sort of reliable, safe and easy inter-thread communication then ZeroMQ is an amazing library.

Programmer, Modeller

Intel Core i7 930 @ 3.5GHz | GeForce 480 GTX | 6GB DDR3 RAM | Windows 7 Premium x64

Visual Studio 2008 | Photoshop CS3 | Maya 2009

Website: http://srichnet.info

Link to comment
Share on other sites

In all seriousness, I want the lowest-level thread access possible so I can understand what is happening on all platforms completely. I also don't like compiling more libs into the engine because almost every time I do there is some little thing I have to fix. I take it I can just start calling pthread commands on Mac, iOS, and Android?:

https://computing.llnl.gov/tutorials/pthreads/#CreatingThreads

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

ZMQ is really a communication pipeline that allows you to sidetrack the whole process of trying to interlock and all that other nasty thread stuff by just implementing fast message passing. Its really good if you're willing to design using their concepts.

 

For pure threading, I might also just point you to TinyThread: http://sourceforge.net/projects/tinythread/

TinyThread++ is a minimalist, portable threading library for C++. It is modeled after the current C++0x standard (draft), implementing a subset thereof, and acts as a simple replacement library for compilers that lack support for C++0x.

 

Kind of sounds like the wrapper class you're making now.

Programmer, Modeller

Intel Core i7 930 @ 3.5GHz | GeForce 480 GTX | 6GB DDR3 RAM | Windows 7 Premium x64

Visual Studio 2008 | Photoshop CS3 | Maya 2009

Website: http://srichnet.info

Link to comment
Share on other sites

C++11 has threading facilities, so I honestly think you are wasting your time to reinvent this...

I think you mean C++0x. But you're correct. Its why I mentioned the TinyThread library, as its an implemented of C++0x.

Programmer, Modeller

Intel Core i7 930 @ 3.5GHz | GeForce 480 GTX | 6GB DDR3 RAM | Windows 7 Premium x64

Visual Studio 2008 | Photoshop CS3 | Maya 2009

Website: http://srichnet.info

Link to comment
Share on other sites

I think you mean C++0x. But you're correct. Its why I mentioned the TinyThread library, as its an implemented of C++0x.

C++11, also formerly known as C++0x (pronounced "see plus plus oh ex wtf lol").

The 11 just means 2011, and the 0x means any year from 2000 to 2009.

Ryzen 9 RX 6800M ■ 16GB XF8 Windows 11 ■
Ultra ■ LE 2.53DWS 5.6  Reaper ■ C/C++ C# ■ Fortran 2008 ■ Story ■
■ Homepage: https://canardia.com ■

Link to comment
Share on other sites

C++11, also formerly known as C++0x (pronounced "see plus plus oh ex wtf lol").

The 11 just means 2011, and the 0x means any year from 2000 to 2009.

Oh interesting. I did not know that.

Programmer, Modeller

Intel Core i7 930 @ 3.5GHz | GeForce 480 GTX | 6GB DDR3 RAM | Windows 7 Premium x64

Visual Studio 2008 | Photoshop CS3 | Maya 2009

Website: http://srichnet.info

Link to comment
Share on other sites

@Josh

 

One nitpick I have is your definition for the Thread class. That was fine back in the days of C, but we have C++ now. ;)

 

#include "../le3.h"

#ifdef WINDOWS
namespace win32
{
       #include <windows.h>
}
#endif

namespace le3
{

enum Thread_State {
	THREAD_FINISHED,
	THREAD_RUNNING,
	THREAD_PAUSED,
	THREAD_READY
};


       class Thread
       {
       public:
               Object* result;

               #ifdef WINDOWS
               HANDLE id;
               Thread_State m_State;
               #endif

               Thread();
               ~Thread();

               virtual void Wait();
               virtual bool Resume();
               virtual bool Pause();
               virtual int GetState();
               virtual Object* GetResult();
       };

       Thread* CreateThread_(Object* EntryPoint(Object* o), Object* o=NULL);
}

 

An enum type is far better suited to this.

There are three types of people in this world. People who make things happen. People who watch things happen. People who ask, "What happened?"

Let's make things happen.

Link to comment
Share on other sites

time wasted

C++11 and Intel Xe are ready to do this and faster....

 

Keep in mind he's looking for a relatively cross platform solution. C++11, while finalized, hasn't been adopted across all compilers and runtimes yet. Intel XE is x86 specific. Neither are really appropriate.

 

Honestly I'm going to have to agree with Metatron here. Boost::thread is the best option currently.

 

@Josh

You really should look into the Boost library. Most of it is all template code and is designed to simply be included in a project and used, not dynamically linked. It's very likely the most commonly used library used with C++ outside of the STL itself.

There are three types of people in this world. People who make things happen. People who watch things happen. People who ask, "What happened?"

Let's make things happen.

Link to comment
Share on other sites

With Windows threads at least, they are supposed to use this type of entry point:

DWORD WINAPI EntryPoint( LPVOID lpParam )

I see 32 bits in and 32 bits out, so is it okay to replace it with this?:

(LPTHREAD_START_ROUTINE)(Object* EntryPoint(Object* o))

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

  • 2 months later...

I added a C++ tag to this thread by editing the first post in the full editor, then moved it to the general programming forum.

 

I don't recommend going through and tagging every single post, but I just wanted to make sure it worked.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...