2016-11-12 68 views
0

我想使用多线程获得200个文件,所以我修改了一个TCL示例如下。 但结果很奇怪,输出文件的总数是随机的,大约135.我很困惑,线程是如何开始改变变量$thread的值。如何在TCL中正确使用循环启动multi-thead?

package require Thread 
puts "*** I'm thread [thread::id]" 

for {set thread 1} {$thread <= 200} {incr thread} { 
    set thread_ida $thread 
    tsv::set app global_thread_num $thread_ida 

    set id [thread::create -joinable { 

     puts [ tsv::get app global_thread_num ] 
     set thread_id [ tsv::get app global_thread_num ] 
     puts "${thread_id}thread_id" 
     set outFile "./test/${thread_id}" 
     append outFile ".tmd" 
     puts $outFile 
     set FileOut [open $outFile w+] 
     puts $FileOut "${thread_id}thread_id" 
    }] ;# thread::create 
    puts "*** Started thread $id" 
    lappend threadIds $id 
} ;# for 
puts "*** Existing threads: [thread::names]" 
# Wait until all other threads are finished 
foreach id $threadIds { 
    thread::join $id 
} 
puts "*** That's all, folks!" 

回答

1

你得到的问题是,这两条线:

puts [ tsv::get app global_thread_num ] 
set thread_id [ tsv::get app global_thread_num ] 

不能保证得到同样的价值可言,也不是在有可能与设置同步所有在外部循环中的共享变量。 Tcl中的线程在启动期间具有合理的开销。

相反,你应该做的是让线程与过程中的工作描述一起,然后用ID发送一个简单的消息给他们开始真正的处理;工作起来要容易得多。

package require Thread 
puts "*** I'm thread [thread::id]" 

for {set thread 1} {$thread <= 200} {incr thread} { 
    set id [thread::create -joinable { 
     proc DoWork {thread_id} { 
      # Only one puts here 
      puts "${thread_id}thread_id" 
      set outFile "./test/${thread_id}" 
      append outFile ".tmd" 
      puts $outFile 
      set FileOut [open $outFile w+] 
      puts $FileOut "${thread_id}thread_id" 
      # Close the channel, please... 
      close $FileOut 
      # Thread done, and since we're using joinable threads it should die now 
      thread::release 
     } 
     thread::wait 
    }] ;# thread::create 
    puts "*** Started thread $id" 
    lappend threadIds $id 
    # Start the work going, passing over the numeric ID in the "message" 
    thread::send -async $id [list DoWork $thread] 
} ;# for 
puts "*** Existing threads: [thread::names]" 
# Wait until all other threads are finished 
foreach id $threadIds { 
    thread::join $id 
} 
puts "*** That's all, folks!" 

这里的关键事情是,我们在每一个线程(DoWork)收到消息,让线程等待消息以thread::wait,然后通过与thread::send -async发送消息启动工作创建一个过程。这项工作破坏了thread::release;它需要明确地这样做,否则它将返回thread::wait等待下一条消息。


我可能会在生产代码中使用线程池,因为它们更容易扩展到特定部署中可用的硬件。 DoWork程序 - 无thread::release - 将在池的-initcmd选项中定义。 thread::send -async将被替换为将作品发布到池中,并且您将等待作业而不是线程。

package require Thread 
puts "*** I'm thread [thread::id]" 

set pool [tpool::create -maxworkers 48 -initcmd { 
    proc DoWork {thread_id} { 
     # Only one puts here 
     puts "${thread_id}thread_id" 
     set outFile "./test/${thread_id}" 
     append outFile ".tmd" 
     puts $outFile 
     set FileOut [open $outFile w+] 
     puts $FileOut "${thread_id}thread_id" 
     # Close the channel, please... 
     close $FileOut 
    }  
}] 

for {set thread 1} {$thread <= 200} {incr thread} { 
    lappend work [tpool::post -nowait $pool [list DoWork $thread]] 
} 
# Wait until all work is finished 
foreach id $work { 
    tpool::wait $pool $id 
} 
puts "*** That's all, folks!" 
tpool::release $pool 
+0

我假设您正在使用的工作负载更加复杂;只需要在单个线程中完成将单个行写入200个文件中的每个文件。 –

+0

我修改我的tcl文件为你的,它的工作原理。非常感谢你〜我终于找到了我的错误〜哈哈。我使用线程来做一些繁重的工作,而不是只写一行到200个文件中的每一个。 –