• Advertisement
Sign in to follow this  

One more doubt in thread.

This topic is 4159 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying now to implement the code that I writed yesterday in the other topic to use that class in a object that will use this type of thread usage. The class that implement the thread was:
#include <pthread.h>

struct Runnable {
	virtual void run() = 0;
};

class Thread {
	public:
		Thread( Runnable *ptr ) {
			_threadObj = ptr;
		}
		void start() {
			pthread_t threadID;
			pthread_create( &threadID, NULL, Thread::threadProc, _threadObj );
		}
	
	protected:
		Runnable *_threadObj;
		static void* threadProc(void* ptr){
			(( Runnable* )ptr)->run();
			return 0;
	}
};



ok, now I want to use this in a sprite class, to start a method of this class in a thread. I'm tryinbg something like this:
class MyObject : public Runnable {
	public:
		virtual void run(){
			std::cout << "Thread complete. " << std::endl;
		}
};

class spriteIII{
	private:
		Thread *thread;
		MyObject *obj;
		
	public:
		spriteIII( ){
			obj = new MyObject( );
			thread = new Thread( obj );
			thread->start();
		}
		void logic(  ){
			std::cout << "Logic!!." << std::endl;
		}
		void render(){
			std::cout << "Render!!." << std::endl;
		}
	
};

........
	std::vector<spriteIII> ts(3);
	//ts.push_back( ts[0] );
	for ( int i=0; i<ts.size(); i++ )
		ts.render();


But what is the output? : Render!!. Render!!. Render!!. Thread complete. As you can see, the method void run(), is done only once. Ok, it's because it's static, but point is: "Get a method in sprite class, that can be run in a thread, independently from one object to another".

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by discman1028
What is the question?


Make each object start it's own thread function, since this class will be inherited by a new one, and so, the this new class can implement different code, for diferent objects eventually instantiated.

Quote:
Original post by paulecoyoteIf you are going along the thought that each sprite should have it's own thread... don't go there. Honestly, it's a bad place.


Why?

Share this post


Link to post
Share on other sites
Quote:
Original post by Tsumuji
Quote:
Original post by discman1028
What is the question?


Make each object start it's own thread function, since this class will be inherited by a new one, and so, the this new class can implement different code, for diferent objects eventually instantiated.

This is still not a question ;) (they typically end with a question mark)

Quote:
Original post by Tsumuji
Quote:
Original post by paulecoyoteIf you are going along the thought that each sprite should have it's own thread... don't go there. Honestly, it's a bad place.


Why?

Imagine you can get 200 sprites on the screen... Having 200 thread will introduce a large overhead that will penalize you in the end.

Moreover, sprite rendering is not something that can be parralelized - you are limited by your use of a single resource - namely, the graphic driver, whose purpose is to serialize the rendering (as of today, I know little hardware that can render 200 sprites in parrallel).

Regards,

Share this post


Link to post
Share on other sites
I'm not trying to do a parallel rendering. I know the this serialization. What I want to implement in parallel is the method logic(). This one will process the IA, collision detection, etc. Any processing that can be done in the CPU.

What I want to know, is how I implement such kind of software ;)
Trying now common C++ lib, but getting the same problems hehehe. I now resumed my code to this:

#include <cc++/thread.h>
#include <iostream>
#include <vector>
using namespace std;
using namespace ost;

class sprite : public Thread{
private:
static int objscounter;
void run(void){
logic( );
}
protected:
virtual void logic( ){
std::cout << "sprite Logic!!." << std::endl;
}
virtual void render( ){
std::cout << "sprite Render!!." << std::endl;
}
public:
sprite(){
objscounter++;
//logic( );
}
~sprite(){}
};
int sprite::objscounter=0;

class custom_sprite : public sprite{
public:
sprite* st;
custom_sprite(){
st = new sprite();
st->start();
}
~custom_sprite(){}
void logic( ){
std::cout << "CTM Logic!!." << std::endl;
}
void render( ){
std::cout << "CTM Render!!." << std::endl;
}
};


int main( int argc, char *argv[] ){
std::vector<custom_sprite> Sprite(3);
for ( uint i=0; i<Sprite.size(); i++ )
Sprite.render();

sleep(2);

return 0;
}




The output:
CTM Render!!.
CTM Render!!.
CTM Render!!.
sprite Logic!!.

The method logic() is run from the base class, not the inherited, and, is run only once. Why this? I think I'm forgetting something from the C++ language....

Share this post


Link to post
Share on other sites
Surely you don't really mean to both inherit from Sprite, and then create one as a member as well?

You should be working with pointers in your vector if you want virtual functions to work properly, though I don't quite see why that would be a problem here.

Share this post


Link to post
Share on other sites
ok, let's go step by step. I think is better, to me pass the problems to you, and you understand correctly my problems that I'm having. If you disagree, tell me ;)
I'm putting a simpler class than before to get a easy view:


class spr : public Thread{
public:
spr(){ this->start(); }
~spr(){}
void run(){
logic();
}
void logic(){
std::cout << "TEST LOGIC()." << std::endl;
}
void render(){
std::cout << "TEST RENDER()." << std::endl;
}
};

-----

vector<spr> S2(4);
/* for ( uint i=0; i<S2.size(); i++ )
S2.start();*/
for ( uint i=0; i<S2.size(); i++ )
S2.render();
for ( uint i=0; i<S2.size(); i++ )
S2.join();



So my question in this first step: How do I set up the thread without calling the method start() from outside? (This code was commented)
If I put the starts to work, (uncommenting them) everything works fine. But I want some automatic thing, since the thread must be obligged to start after the object is instantiated. But in the way I do now, the thread does not start.

Share this post


Link to post
Share on other sites
Quote:
Original post by Emmanuel Deloget
This is still not a question ;) (they typically end with a question mark)


I'm glad you agree, I thought I was going nuts..

Share this post


Link to post
Share on other sites
It looks like your Thread class doesn't obey the rule of three:
Quote:
Rule of Three
If a class requires at least one out of the copy-constructor, destructor and copy-assignment operator it generally needs all three.

When you create a vector< T > with an initial size it is filled with copies of either a given T object, if provided, or a default initialised T object if not. So the line vector<spr> S2(4); is creating a default initialised spr and then copy-constructing four spr instances from that default initialised spr instance. I suspect copy-construction is not implemented correctly and so those four copies all represent exactly the same thread, rather than four separate threads. That single thread then gets started four times.

Σnigma

Share this post


Link to post
Share on other sites
OK, was able to load things. But I have noticed something. I'm unnable to start more than 384 threads by this app. There's some lilmitation to the number of threads that a app can start? How can I see this limit?

Share this post


Link to post
Share on other sites
Quote:
Original post by Tsumuji
OK, was able to load things. But I have noticed something. I'm unnable to start more than 384 threads by this app. There's some lilmitation to the number of threads that a app can start? How can I see this limit?


Yes, you are limited - not by the thread count, but by your system memory. See this explaination for further information. Anyway, creating 384 threads in a single process is something I'd accurately describe as "freaking insane" - unless you have 384 CPU or CPU cores [smile].

Regards,

Share this post


Link to post
Share on other sites
If you want 300+ threaded off tasks, you might want to think about using a "thread pool" pattern.

Windows has a few thread pool APIs for both C++ and C#. I've also seen other implementations based off of pthreads.

Share this post


Link to post
Share on other sites
- I like to crash my machine ;)

- The thread pool idea is good, but my threads will be instantiated on demand. No, the app will not use that much threads at once, at least, not all the time. App will use normally 3, maybe 4 threads at once. So, no problem in starting and ending threads all the time. And, if this become a problem, I'll implement some time of optimization to do not let threads, start and stops, consume too much processing power.

- I'm on linux ;)

Share this post


Link to post
Share on other sites
Quote:
Original post by Tsumuji
- The thread pool idea is good, but my threads will be instantiated on demand. No, the app will not use that much threads at once, at least, not all the time. App will use normally 3, maybe 4 threads at once. So, no problem in starting and ending threads all the time. And, if this become a problem, I'll implement some time of optimization to do not let threads, start and stops, consume too much processing power.


you do realize, right, that you can only have as many threads concurrently running as you have cores? i.e. even if you have 1000 threads, only 2 of them will be actually running in parallel on a dual core machine (the other 998 will be waiting for a core to process them). there is a cost to switch between threads which means that 999 threads to process sprites is massively less efficient than one thread to process 999 sprites.

thread doesn't mean parallel, it means can run on it's own core. Therefore, you don't actually gain any performance benefit for having more threads than cores. What you gain is context switching (i.e. you can load some data while the game appears to continue running; they don't actually run in parallel unless you have enough cores for each thread).

-me

Share this post


Link to post
Share on other sites
Each thread uses up a big chunk of address space -- 1 meg is quite common. On a 32 bit system, 300 threads would consume way more address space than you'd want to give up.

If the threads are only running on demand, then a thread pool model makes a heck of alot of sense.

Do you need to preserve your Stack State for your Threads for a long period of time, or would it be easy to serialize the State you need into a struct or class?

If that is the case, the Task model makes more sense than using a bunch of Threads.

A Task is a function, some state data, and a condition under which the Task should execute. The manager of the Tasks has access to a pool of threads, which are reused to run whatever Task needs them.

This reduces the amount of state in your system (because Tasks, instead of having the implicit state of an entire stack, now only have explicit state between runs), reduces the number of threads you have running, and saves on address space wasteage.

Tasks can be set to run based off an event being triggered, or pretty much any custom reason you want and that the task manager you wrote understands.

Share this post


Link to post
Share on other sites
Quote:
Original post by Tsumuji
I modified here the stack size, but gimmes no change.


Sorry Tsumuji, got distracted with the rest of the chat. :)

Your problem is you have a copy constructor that you didn't implement or disable.

Note that you didn't implement a destructor either. When you allocate memory in the constructor, you should make sure you clean it up in the destructor.

And, every class with a non-trivial destructor needs to implement a copy constructor and operator=. Either implement, or disable them.

Change your spriteIII as follows, and it will show you what is going wrong:

class spriteIII{
private:
Thread *thread;
MyObject *obj;

public:
spriteIII( const spriteIII& other ) {
std::cout << "Copy!! Oh crap, doesn't work!!" << std::endl;
}
spriteIII const&operator=( const spriteIII& other) {
std::cout << "operator=!! Oh crap, doesn't work!!" << std::endl;
}
spriteIII( ){
obj = new MyObject( );
thread = new Thread( obj );
thread->start();
}
void logic( ){
std::cout << "Logic!!." << std::endl;
}
void render(){
std::cout << "Render!!." << std::endl;
}

};


Understand the problem?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I think you haven't been noticed. I changed the code, so now, I use gnu common c++ for threads. Is a good library, boost is too big! So I'm using this one.
My new classes are:

#include <cc++/thread.h>
#include <iostream>
#include <vector>
#include <errno.h>
using namespace std;
using namespace ost;

class spr : public Thread{
public:
spr(){
// std::cout << "TEST CONSTRUCTOR()." << std::endl;
if ( start() != 0 )
perror(NULL);
// std::cout << "STARTED THREAD " << getId() << std::endl;
n++;
}
protected:
static unsigned int n;
virtual ~spr(){
// std::cout << "TEST DESTRUCTOR()." << std::endl;
}
void run(){
logic();
}
virtual void logic(){
// std::cout << "TEST LOGIC()." << std::endl;
}
virtual void render(){
// std::cout << "TEST RENDER()." << std::endl;
}
};
unsigned int spr::n=0;
class cspr : public spr{
private:
int _id;
public:
cspr(){
_id = n-1;
// std::cout << "sprite started." <<_id<< std::endl;
}
~cspr(){
// std::cout << "finalizing!!!" << std::endl;
}
void logic(){
//std::cout << "processing " << id() << "!!!" << std::endl;
// std::cout << "Thread id: " << getId() << std::endl;
this->sleep(10000); //milisecs
return;
}
void render(){
//std::cout << "rendering!!!" << std::endl;
}
int id(){ return _id; }
};
int main( int argc, char *argv[] ){

uint qt = 385;
cspr *S2 = new cspr[qt]();
for ( uint i=0; i<qt; i++ )
S2.render();
for ( uint i=0; i<qt; i++ )
S2.join();
// for ( uint i=0; i<qt; i++ )
// S2.~cspr();

pthread_attr_t attr;
size_t stacksize;
pthread_attr_init(&attr);
pthread_attr_getstacksize (&attr, &stacksize);
printf("Default stack size = %d\n", stacksize);

return 0;
}




The thread limit persists, BUT, I tryed this in anither machine, with 1GB RAM and Suse 64. Was able to start 8100 threads! OK, the problem is memory. BUT(again), I tryed a code similar to this one, in java, and what happens? Was able to start 50000+ threads on this machine(256MB)! What are the differences? Why I can start 50k threads in java but not in C++? I think it is possible to do something similar from the java logic? This is good at al?

Share this post


Link to post
Share on other sites
I almost puked on the keyboard when I read this thread.

Anybody trying to use more than a handful of threads should not be programming or at least learn the basics of how a computer works. Seriously no offence but your idea is utter crap and you are not using threads properly at all and not only are you confusing the design but also because of overhead and context switches your performance will be utterly poor. The maximum number of threads you should be using (and by this I mean the utter maximum in most cases) is NumberOfPhysicalCPU * 2, and ideally you only want one per physical although in some cases (single core processors) you will want to use a background thread for resource loading, etc.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
I tryed a code similar to this one, in java, and what happens? Was able to start 50000+ threads on this machine(256MB)!

Wow, thats actually kinda impressive, in a sick sort of way.

Now do something useful with it. [rolleyes]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I will not use 50k threads! Is just a comparision :) a teste... you know...

Share this post


Link to post
Share on other sites
There are very few reasons to create an OS thread:
1) Multiple tasks executing simultaneously (1 thread per CPU/core)
2) Block until alerted, then respond and repeat (ex: I/O Completion Ports, or having a GUI thread that keeps the interface responsive while other threads do long processing)

There might be a few more situations where threads are appropriate, but in most other cases threads just make your program run slower. Each time a cpu switches threads, cache coherency can be lost, which can be a HUGE slowdown if your program access a lot of data.

If you want to simulate independant objects updating in a 'nearly simultaneous' manner, do something like:
for_each(
AllObjects.begin(),
AllObjects.end(),
mem_fun(&Object::Logic));

//or

for_each(
AllObjects.begin(),
AllObjects.end(),
bind2nd(mem_fun(&Object::Logic),
LogicParameter));

and just let them update sequentially.

As for why you get different results from java, are you sure it's actually creating the threads and not simply adding them to a 'list of threads to create soon' or even 'list of functions to run to simulate threads'? No telling how the VM handles the threads - they might even get optimized out, or they might run immediately then exit to make room for new threads, etc. It really depends on _exactly_ what is going on everywhere, which is why threads are something you don't often see in program proofs (similar to the way globals are frowned upon)

Share this post


Link to post
Share on other sites
Quote:
Original post by Extrarius
As for why you get different results from java, are you sure it's actually creating the threads and not simply adding them to a 'list of threads to create soon' or even 'list of functions to run to simulate threads'? No telling how the VM handles the threads - they might even get optimized out, or they might run immediately then exit to make room for new threads, etc. It really depends on _exactly_ what is going on everywhere, which is why threads are something you don't often see in program proofs (similar to the way globals are frowned upon)


I was thinking in something like that. Maybe this is correct, so, I'll use the class this manner. Just put more memory if more threads is needed :)

OK, so now, a more cplicated task(I think): How to put the class cspr in a vector(or other thing), to make things dinamically loadable? What I want is make an array of objects that can be easily modificated. Some members(objects in the array in any index) will destructed, while new others will be appended. The std::vector does not work very well for this task as I saw.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement