• Post Reply Bookmark Topic Watch Topic
  • New Topic

Initializing a class in a thread

 
Leslie Chaim
Ranch Hand
Posts: 336
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have a typical boss/worker scenario for all the normal processing. For speed purposes, I want to extend the boss/worker concept and place the initialization of the worker class in the thread. This way, the boss (or caller) can begin normal processing sooner.
For the real implementation, I would like to use whatever is already available and would appreciate any links for this purpose. For example something like this.
Here, and for the purpose of discussion, I am just looking for better understanding.
I came up with the following (somewhat pseudo) code.
The Worker is looks like this:

And the Boss...

Your thoughts are greatly appreciated.
Thanks,
Leslie
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hmmm... it's a bit hard to follow. I assume that somewhere there should be code that actually start()s the Thread for each
worker? And somewhere there will be code that sets done = false? Then there's a nameless method in the Boss class which seems to be designed to wait until all the Workers have completed their initialize() - at least, it counts how many times it's been notified, and the end of initialize() seems to be the only place notify() is called from (though that's not guaranteed since the lock/gate object is supplied from elsewhere it appears.) There's a risk here - it's possible that one or more threads might complete their initialize() and call notify() before the first wait() is reached, or while some of the other loop code (other that wait() itself) is being executed. If this happens, notify() has no effect, and the workersInitialized count will be incorrect. The loop will never terminate because even after all threads are initialized, workersInitialized < numClients. I'd give the Boss class a new method, someting like incrememntInitializedCount() (package access?), which allows a Worker to tell the Boss when it's done with initialization. Make it synchronized - it should be able to count how many times a Worker has called the method, regardless of whether the Boss is in wait() or doing something else. You still want the wait()/notify() to ensure the Boss only wakes up when there's something to respond to. But don't assume that the number of times it's received notify() while in wait() mode is equal to the number of times notify() was called; that may not be the case.
The other thing to consider (perhaps first) - does the Boss even need to wait for all the threads to initialize? In the code shown, the Boss doesn't actually do anything after the initialization is complete, so it doesn't matter much if the Boss was waiting or not. Does the Boss have something else it needs to do? If so, is it really something that has to wait until the initializations are complete? If not, you might just skip the whole wait()/notify() section as unnecessary.
Hope that helps...
 
Leslie Chaim
Ranch Hand
Posts: 336
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hmmm... it's a bit hard to follow.
But I see you plowed through
I assume that somewhere there should be code that actually start()s the Thread for each
worker? And somewhere there will be code that sets done = false?

Yes, you are correct (as usual ). My goal is to enhance an existing application and for the posting purposes, I wrote this code just to get you an idea. I guess I could have done better .
For instance the thread in my application code is as follows:

So yes, I just missed to start() the thread in the Worker constructer. The same goes for the done flag.
Then there's a nameless method in the Boss class
Yikes! Nitpicking in progress , I love it.
which seems to be designed to wait until all the Workers have completed their initialize() - at least
Correct, and that nameless method is the Boss constructor!
it counts how many times it's been notified, and the end of initialize() seems to be the only place notify() is called from (though that's not guaranteed since the lock/gate object is supplied from elsewhere it appears.) There's a risk here - it's possible that one or more threads might complete their initialize() and call notify() before the first wait() is reached, or while some of the other loop code (other that wait() itself) is being executed. If this happens, notify() has no effect, and the workersInitialized count will be incorrect. The loop will never terminate because even after all threads are initialized, workersInitialized < numClients.
I knew (from the many books which I have read on threading) that something was bothering me; I just could not remember what it was. And this is it. Thanks!
I'd give the Boss class a new method, someting like incrememntInitializedCount() (package access?), which allows a Worker to tell the Boss when it's done with initialization. Make it synchronized - it should be able to count how many times a Worker has called the method, regardless of whether the Boss is in wait() or doing something else. You still want the wait()/notify() to ensure the Boss only wakes up when there's something to respond to.
Interesting idea, OK, remember that this was the purpose of discussion and better understanding, I guess I need to go deeper here and talk a little about another mechanism that I already use for the actual 'processing' -- a Barrier class:

The Barrier is a static member in the Worker class and initialized as follows:

The run() again, is somewhat like this:

So each Worker hits the barrier and then it then notify()s through the gate object for which the Boss is wait()ing. (BTW, is the phrase correct?)
What do you think about this approach0? I think I will just use this technique for the initialization process.
But don't assume that the number of times it's received notify() while in wait() mode is equal to the number of times notify() was called; that may not be the case.
Could you elaborate more on this (and why)?
The other thing to consider (perhaps first) - does the Boss even need to wait for all the threads to initialize?
I think it does Have you seen the comments in initialize().
In the code shown, the Boss doesn't actually do anything after the initialization is complete, so it doesn't matter much if the Boss was waiting or not. Does the Boss have something else it needs to do?
It sure does -- the actual processing. I just wanted to focus on the threading aspect. Sorry, that I keep on repeating myself
Hope that helps...
It sure got me thinking, and I am looking ahead for your response.
Thank you,
Leslie
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
[JY]: But don't assume that the number of times it's received notify() while in wait() mode is equal to the number of times notify() was called; that may not be the case.
[LC]: Could you elaborate more on this (and why)?

Primarily because if notify() happens to be called while the Boss thread is not doing a wait(), there will be no effect. Now once the Boss enters that sync block, it's always holding onto the sync lock except while it's int the wait(), and the only way notify() can be issued by another thread is if that thread has acquired the lock, so we can guarantee that one the sync block has been entered by Boss, any notify() can only be issued if the Boss is in wait(), so the Boss is guaranteed to recevie it. (Originally I forgot about this, and thought you had a bigger problem here than you really do.) But there's still the pesky question of what about any workers that issue a notify() before the Boss enters the sync block. Well, one way around that is to start the Workers from within that same sync block, immediately after the sync is acquired. If the Workers haven't even been started until after you've entered the sync block, there's no way they can complete initialize() before they sync block. OK, problem seems solved.
Now there's another possible hole - we don't know, from the code shown, if any other threads have access to the Boss's lock object. The Boss was passed this object as a parameter to a public method; since it was created elsewhere, we don't really know anything about who else might be doing something with that object. If another thread decides to call lock.notify() for any reason, they can also screw up our count. So I'd favor using a private lock object, inaccessible outside the Boss class, and the trusted Workier instances which the Boss has passed it to.
[JY]: The other thing to consider (perhaps first) - does the Boss even need to wait for all the threads to initialize?
[LC]: I think it does Have you seen the comments in initialize().
[JY]: In the code shown, the Boss doesn't actually do anything after the initialization is complete, so it doesn't matter much if the Boss was waiting or not. Does the Boss have something else it needs to do?
[LC]: It sure does -- the actual processing.

OK. I'm going to guess that once everyone is initialized, the Boss is going to start assigning tasks to the Workers somehow. But I'm not at all sure the Boss needs to wait to do this. Consider an analogy with a group of office workers. The Boss comes in at 7:00 AM with a list of tasks for the workers to do today. The rest of the staff comes in between 7:30 AM and 8:30 AM, and when they arrive they may need some time to get coffee & donuts, delete their daily spam, etc. So, what should the Boss do? One option is to wait until each and every office worker has arrived and finished their donuts, then go around and assign tasks. This gets everyone started about 9:45 AM. Or, the Boss could write down each task on a slip of paper, and leave a task for each worker on their desk where they'll see it when they come in, and once theyre ready to start work, they can do so. This would seem to be much more efficient, allowing the early workers to start sooner. The only catch is, you need to make sure that everyone in the office knows to check their desk for notes from the Boss when then come in. If some workers come in and immediately put the donut box on their desk, then later throw away the donuts and accidentally take the note with it, that's a problem. It shouldn't be too difficult to fix this though - you jut need to make sure everyone knows to be careful not to lose or forget any notes while they're eating donuts.
So analogously, in your program you get to decide how the Boss will tell each Worker what to do. With a little careful design it can probably be done in such a way that the Boss can give a Worker a Task even before initialize() cas completed. Probably the worker can have a setTask() or addTask() method (synchronized) which allows the Boss to give it an assignment. Or maybe there's a single Queue somewhere, and the Boss jsut puts tasks on the Queue, and Workers know to keep checking the Queue for new tasks. As long as there's some sort of communication protocol that is unaffected by initialize(), and which is thread-safe, the Boss shouldn't have to wait for all the workers before handing out assignments.
Unless of course I've guessed completely wrong about what the Boss plans to do with the Workers once they're ready. Which has been known to happen...
I've looked at the Barrier/Worker code, but I don't really have enough understanding of what the intent is to comment on whether it's appropriate. There seem to be three different classes of object performing notify() or notifyAll(), but I'm not sure what each means. Perhaps these calls could be wrapped in simple methods with names communicating intent? E.g. from studying the code related to resets, we could even make a small class just for code related to resets:

Then other code just says resetter.reset() or resetter.waitForReset(), which seems a little clearer to me. Or, in the Worker run() method, we could refactor to something like:

I dunno if that helps you any; I realize you were just providing a simplified view of the code. But I find that it helps me to understand things better when I have lots of little methods with good descriptive names.
Enjoy...
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!