M
Marcin Rodzik
Hello,
I have a thread (the essential piece of its code can be found here:
http://pastebin.com/KM8Yiqgs) which sends some objects ("tasks") over
the network (in method tryToSendTask). Another thread submits objects
to be sent by means of the first thread's method submit - namely, the
"task" is put into queue.
The sending thread "goes to sleep" when the queue is empty but is
woken up if someone calls its submit method. The problem is that we
need to flush the stream before letting the thread sleep. It might be
a little time-consuming operation, so I do it outside synchronized
section (lines 25-31). The problem is that meanwhile someone can add a
new task to the queue. Moreover, before going definitely to sleep
(line 35), I check some flags which can tell me that someone wants my
thread to finish (goOn=false means finishing no matter what,
waitableClosing=true means that we should finish the thread after
sending out the last task from the queue, i.e. only if the queue is
already empty).
My biggest concern is to avoid the following scenario:
- due to discovering that the queue (line 19) is empty the output
stream is flushed
- during flush some objects are added to the queue and flag
waitableClosing is set to false
- let's assume that there is no line 29 in my code
- due to waitableClosing=true the thread ends (goOn=false is set in
line 31)
- as a result, last task objects are never sent
This scenario is something I didn't think about on the beggining, so
after some debugging I decided to add line 29 But now I'm afraid of
the weird synchronization thing. Let's assume that the flags goOn and
waitableClosing are synchronized on the this reference, but the task
queue has its own synchronization. Is it possible that my thread will
see the old (not refreshed) state of the queue (i.e. empty) but the
new value of the flag responsible for ending the thread? Which would
mean that the bug is still present in my code...
A possible remedy involves adding the synchronized attribute to the
entire submit method, but using a synchronized collection then seems
to be an overkill. On the other hand, we have to add a synchronized
section around line 24 where we read the state of the queue...
....don't we? Maybe we don't. Determining the queue is empty costs us
flushing the stream, but then the state of the queue will be checked
again in line 34 (inside the synchronized section).
What do you think?
Marcin
I have a thread (the essential piece of its code can be found here:
http://pastebin.com/KM8Yiqgs) which sends some objects ("tasks") over
the network (in method tryToSendTask). Another thread submits objects
to be sent by means of the first thread's method submit - namely, the
"task" is put into queue.
The sending thread "goes to sleep" when the queue is empty but is
woken up if someone calls its submit method. The problem is that we
need to flush the stream before letting the thread sleep. It might be
a little time-consuming operation, so I do it outside synchronized
section (lines 25-31). The problem is that meanwhile someone can add a
new task to the queue. Moreover, before going definitely to sleep
(line 35), I check some flags which can tell me that someone wants my
thread to finish (goOn=false means finishing no matter what,
waitableClosing=true means that we should finish the thread after
sending out the last task from the queue, i.e. only if the queue is
already empty).
My biggest concern is to avoid the following scenario:
- due to discovering that the queue (line 19) is empty the output
stream is flushed
- during flush some objects are added to the queue and flag
waitableClosing is set to false
- let's assume that there is no line 29 in my code
- due to waitableClosing=true the thread ends (goOn=false is set in
line 31)
- as a result, last task objects are never sent
This scenario is something I didn't think about on the beggining, so
after some debugging I decided to add line 29 But now I'm afraid of
the weird synchronization thing. Let's assume that the flags goOn and
waitableClosing are synchronized on the this reference, but the task
queue has its own synchronization. Is it possible that my thread will
see the old (not refreshed) state of the queue (i.e. empty) but the
new value of the flag responsible for ending the thread? Which would
mean that the bug is still present in my code...
A possible remedy involves adding the synchronized attribute to the
entire submit method, but using a synchronized collection then seems
to be an overkill. On the other hand, we have to add a synchronized
section around line 24 where we read the state of the queue...
....don't we? Maybe we don't. Determining the queue is empty costs us
flushing the stream, but then the state of the queue will be checked
again in line 34 (inside the synchronized section).
What do you think?
Marcin