| Ticket UUID: | 674367 | ||
| Title: | call for a function that is not thread safe | ||
| Type: | RFE | Created on: | 2003-01-24 23:39:57 |
| Submitter: | elfring | Assigned to: | vasiljevic |
| Subsystem: | 80. Thread Package | Severity: | |
| Priority: | 5 Medium | Last modified: | 2003-11-09 23:26:00 |
| Status: | Open | Closed by: | |
| Resolution: | None | Closed on: | |
| Version: | None | ||
| Description: | ||||
I describe an use case for the handling of unsafe functions calls with
the thread package.
I must assume that an application
programming interface (like a graphics library or a music API) or even
a single function is not thread safe if this property is not described in the
documentation for that API.
So I must ensure that all unsafe
functions are executed by a single thread at each time. I want to create a
thread for each function library that must be handled as it has not
implemented thread safety at startup/initialization time of my
application. I want to achieve that calls into different unsafe libraries
can be executed simultaneously.
I can perform the call with the
function "thread::send" for a thread that has been created before. But I
think that I will need a special kind of mutual exclusion. I understand the
thread package's documentation in the way that a mutex that is created
by the command "thread::mutex create" belongs to the calling thread.
It may not be stored in a thread shared variable. Please correct me if I
make wrong assumptions here.
I guess that the function
"thread::eval" does not all what I want and need here. It does not expect
a thread indentifier in its argument list.
I need a mutex that is global to
the process scope
(http://citeseer.nj.nec.com/cs?cs=1&q=synchronization+and+global+and+mutex&submit=Documents&co=Expected+Citations&cm=50&cf=Any&ao=Expected+Citations&am=20&af=Any
)
to perform a protected and synchronous call of a code piece that
should be executed by an other thread.
I would like to suggest new
functions like the following.
1. thread::mutex::create
global
or
thread::mutex -global create
2.
thread::safecall id global_mutex script ?varname?
How
do you think about this suggestion?
Does this use case lead to add
more synchronization primitives to the thread package?
| ||||
| User Comments: | ||||
elfring added on 2003-01-25 16:10:09:
Logged In: YES user_id=572001 Values are only available globally with TCL threads if the data is stored in thread shared variables. (http://cvs.sourceforge.net/cgi- bin/viewcvs.cgi/*checkout*/tcl/thread/doc/html/tsv.html). So I adjust my suggestion for the function interface design. The identifier for the mutex object with the global scope must be accessed by a thread shared variable. 1. thread::mutex::create ?tsvname ...? 2. thread::safecall id tsvname script ?varname? vasiljevic added on 2003-01-25 16:57:48:
Logged In: YES
user_id=95086
Mutexes created with "thread::mutex create" are
already in the global scope.
They can be used from any thread. A mutex tied to a thread
has no real benefit. So you're perfectly ok with that.
The mutex indentifier returned by "thread::mutex create" can
be passed to another thread or stored in the thread shared
variable (array) and used from other threads as well.
Also, thread::eval is a nice shortcut of
thread::mutex lock $mutex
# do some Tcl work
thread::mutex unlock $mutex
so you can just say:
thread::eval -mutex $mutex {
# do some Tcl work
}
The benefit is: you can never forget to unlock the
mutex. Also, In case of script error, the implementation
guarantees that the mutex will be unlocked. Without this
you must take care yoursefl about unlocking the mutex
which may prove complicated in some cases.
A very simplified use of thread eval is:
thread.:eval {
# do some Tcl wor
}
where the mutex is implicit and this way you can be sure
that only *one* thread at a time in the entire process can
run the Tcl code.
elfring added on 2003-01-26 20:54:49:
Logged In: YES
user_id=572001
1. Thanks for your answer.
Please add to the documentation that the TCL
mutexes have got global scope.
(The mutex identifiers should not be
stored in local variables. They must be stored in thread shared variables to be
useable by all threads.)
2. But I think that something is still missing for
the suggested function "thread::safecall id tsvname script
?varname?".
I want that a different thread does something with
"thread::eval -mutex". How will the calling thread get the return values from the
called thread?
3. Will the (missing) sychronization primitives that
are described in the chapter "2.3. Interprocess Communication" of the
book "Modern Opreation Systems"
(http://www.cs.vu.nl/~ast/books/mos2/) be added to the thread package?
elfring added on 2003-01-26 21:07:54:
Logged In: YES user_id=572001 1. And your explanation "... this way you can be sure that only *one* thread at a time in the entire process can run ..." is easier to understand than the current description "If no mutex is specified ... an internal static mutex is used". (http://cvs.sourceforge.net/cgi- bin/viewcvs.cgi/*checkout*/tcl/thread/doc/html/thread.html) elfring added on 2003-01-27 05:16:24:
Logged In: YES
user_id=572001
2. Or will the following code example do what I want?
set $TID
[thread::create -preserved]
tsv::set X myMutex [thread::mutex
create]
thread::send $TID \
{
thread::eval -lock [tsv::get X
myMutex] {open Test.txt}
} File
puts $File Hallo
close
$File
thread::mutex destroy [tsv::get X myMutex]
thread::release
$TID
vasiljevic added on 2003-01-27 15:25:51:
Logged In: YES user_id=95086 This example will instruct the $TID thread to open the Test.tst file under lock. If you however want to both open and write to the file in atomic way, you should move the "puts $File" in the thread::eval block. Normally, your application will create some mutexes up front and store them in the shared variable. Those live a long as the app lives and are generally never destroyed. During runtime, threads come and go and they use the precreated mutexes for various sync tasks. elfring added on 2003-01-27 20:07:44:
Logged In: YES
user_id=572001
1. Please add your better explanation to the documentation.
2. My intention is just to execute a single function calll under the
lock protection.
But I think that I will not get the return code of the "unsafe"
function "open" in my first version of the example. I will get the
return value of the function call "thread::eval" instead. How do
you think about it?
set $TID [thread::create -preserved]
tsv::set X myMutex [thread::mutex create]
thread::send $TID \
{
thread::eval -lock [tsv::get X myMutex] {catch {open Test.txt w}
Test}
return $Test
} File
puts $File Hallo
close $File
thread::mutex destroy [tsv::get X myMutex]
thread::release $TID
Can the retrieval for return values from other threads made
easier?
Does the second example show a use case that can be
supported by a single function in the TCL threads API?
vasiljevic added on 2003-01-27 21:15:05:
Logged In: YES
user_id=95086
Well, returning of values from threads, using the thread::send
is already damn-simple. I do not know how to make it simpler.
It is either:
set result [thread::send $tid "set somevar 12"]
or
thread::send $tid "set somevar 12" result.
What can be simpler than this?
If you want to eval the script in an atomic fashion
in the other thread, one can perhaps say:
thread::send -lock myMutex $tid {open file.txt} result
Would this satisfy your requirement?
elfring added on 2003-01-28 00:03:15:
Logged In: YES user_id=572001 Well, your last command seems to be very close to my wish. 1. I just do not read an option "-lock" for the function "thread::send" in the HTML documentation at the moment. 2. What will happen if the script that is executed this way by the other thread will "throw" an error? Can the error be caught? vasiljevic added on 2003-01-28 00:49:45:
Logged In: YES
user_id=95086
1. There is none yet. It was just an idea to see if it would fit.
2. Of course, Just make the catch
catch {thread::send $tid $script}
or examine return value of:
thread::send $tid $script result
to be 1
Note that "thread::send $tid $script result" is the same as
you would do with:
catch {thread::send $tid $script} result
BTW, do you mind going to the mail-list for some discussions
as Donal suggested? When we come to some nice conclusion
we (or you) might post the feature request/bug etc so we do
not clutter the SF. It is much more easier to me to answer
your questions over email.
elfring added on 2003-01-28 03:38:37:
Logged In: YES user_id=572001 1. Please add it. I like because it seems to be exatly the enhancement I want. 2. Please add this to the documentation. 3. Yes. Let us continue the discussion on the new mailing list "tcl-threads". elfring added on 2003-05-11 22:08:56:
Logged In: YES user_id=572001 Where and when will our discussion be continued? Here or at the mailing list (more synchronization primitives for the threads package - https://sourceforge.net/mailarchive/forum.php?thread_id=1585197&forum_id=24972)? elfring added on 2003-06-24 22:41:27:
Logged In: YES user_id=572001 I assume that the requested function can be implemented with condition variables. But I see an important detail. - The called thread should perform a "thread::cond wait" for the calling thread. The caller will be woken up after the sent script was executed. The scheduling strategy for the calling threads will be an interesting part in the solution. elfring added on 2003-07-13 20:04:33:
Logged In: YES user_id=572001 I hope that my requests "https://sourceforge.net/tracker/?func=detail&aid=770193&group_id=7586&atid=357586" (Boost C++) and "https://sourceforge.net/tracker/?func=detail&aid=712663&group_id=7232&atid=357232" (ZThread) will help for this topic. elfring added on 2003-07-13 23:08:16:
Logged In: YES user_id=572001 Example: It is described on the page "http://tcljava.sourceforge.net/docs/website/getstart.html" how the function "eval" must be protected against multithreaded calls. vasiljevic added on 2003-07-14 01:36:25:
Logged In: YES user_id=95086 Your assumption about mutexes is wrong. Mutex handles can be shared among threads since very nature of the mutex is to synchronize access from many threads. So, handles to mutexes created with tnread::mutex create can be left in thread shared arrays and accesed from many threads simultaneously. The thread package contains examples of Tcl code (web server and command server) where sync techniques with mutexes and condition variables are employed. Zoran elfring added on 2003-09-07 19:57:48:
Logged In: YES user_id=572001 1. Are you going to add this description to the documentation? 2. I am looking for a monitor implementation that has got the scope of a library or package and not a single synchronized method or block like it is an Java. A function call will get this monitor as a parameter. elfring added on 2003-11-07 01:30:28:
File Added - 66690: MonitoredExecutor.zip Logged In: YES user_id=572001 I have published the uploaded file also in the forum "class for function calls that are not thread safe" (http://groups.google.de/groups?th=ee30cb7159ff86eb&group=comp.programming.threads). Can it improve TCL source code? elfring added on 2003-11-07 04:23:36:
File Deleted - 66690: elfring added on 2003-11-07 04:25:22:
File Added - 66706: MonitoredExecutor.zip elfring added on 2003-11-09 02:21:11:
File Deleted - 66706: elfring added on 2003-11-09 02:24:46:
File Added - 66887: MonitoredExecutor.zip Logged In: YES user_id=572001 I have added a TCL file. I hope that this source code variant can help to express my ideas and concepts on this topic. elfring added on 2003-11-09 23:26:00:
Logged In: YES
user_id=572001
# Would this implementation have the same effect?
namespace eval monitored_executor \
{
namespace export do new delete
proc do {id work} \
{
return [thread::send $id $work]
}
proc new {} \
{
return [thread::create -preserved]
}
proc delete (id) \
{
thread::release $id
}
}
# Did my last point of view from C/C++ make it harder to see the TCL functionality?
# Can the requested option "-lock" help if the function "send" is synchronously and completely processed?
| ||||
Attachments:
- MonitoredExecutor.zip [download] added by elfring on 2003-11-09 02:24:46. [details]
