Saran
Saran

Reputation: 366

Tcl Thread : How to access global variables in thread

I have a proc named "startMyProc {num}". I want this proc to be called by two different threads and wait for both the threads to complete. I tried the solution given which is working. I want to access the global variables in startMyProc and call a another proc "startMyAnotherProc {num}". How can this be done?

package require Thread


global myVar

set myVar false

set id1 [thread::create -joinable {
    source sample.tcl
    thread::wait
    }]
set id2 [thread::create -joinable {
    source sample.tcl
    thread::wait
    }]

set num 1
thread::send -async $id1 [list startMyProc $num]
set num 2
thread::send -async $id2 [list startMyProc $num]

thread::join $id1
thread::join $id2

My sample.tcl looks like this,

proc startMyProc { num } {
    global myVar
    puts $myVar
    puts "Opening $num"
    after 2000
    puts "Opening $num"
    after 2000
    puts "Opening $num"
    after 2000
    startMyAnotherProc $myVar
    return
}

proc startMyAnotherProc { num } {
    puts "Opening Another Proc: $num"
    after 2000
    puts "Opening Another Proc: $num"
    after 2000
    return
}

Upvotes: 2

Views: 2889

Answers (1)

Donal Fellows
Donal Fellows

Reputation: 137567

Each thread has its own complete interpreter, isolated from all the other interpreters in your program (except for the thread package's commands' capabilities). The simplest, most direct way of getting the procedure in all the threads is to put it in a script file and then source that as part of the startup script of the thread:

set t1 [thread::create -joinable {
    source myProcedures.tcl
    startMyProc $num
}]
set t2 [thread::create -joinable {
    source myProcedures.tcl
    startMyProc $num
}]

You'll run into another problem though. Variables are also not shared. That means that you're not going to get $num over. You should really make the scripts start up and then do thread::wait at the end. You can then thread::send them the work (and get the substitutions right when building the script).

set t1 [thread::create -joinable {
    source myProcedures.tcl
    thread::wait
}]
set t2 [thread::create -joinable {
    source myProcedures.tcl
    thread::wait
}]
thread::send -async $t1 [list startMyProc $num]
thread::send -async $t2 [list startMyProc $num]

However, if you are really thinking in terms of sending tasks to worker threads, you should look at the thread pool (tpool) support; it's much easier to scale up.

# Make the thread pool
set pool [tpool::create -initcmd {
    source myProcedures.tcl
}]

# Sent the work into the pool as distinct jobs
set job1 [tpool::post $pool [list startMyProc $num]]
set job2 [tpool::post $pool [list startMyProc $num]]

# Wait for all the jobs in the pool to finish
set waitingfor [list $job1 $job2]
while {[llength $waitingfor] > 0} {
    tpool::wait $pool $waitingfor waitingfor
}

# Get results now with tpool::get

# Dispose of the pool
tpool::release $pool

Upvotes: 5

Related Questions