[ruby-core:35397] [Ruby 1.9 - Bug #4405] WIN32OLE & Threads incompatible

简单的说, win32ole是线程不安全的, 如果在thread里面去调用它, 就会报错

 

 

Issue #4405 has been updated by Thomas Enebo.

英文部分来自: http://fossplanet.com/f14/%5Bruby-core-35397%5D-%5Bruby-1-9-bug-4405%5D-win32ole-threads-incompatible-109229/


JRuby's implementation should be prone to the same problems when accessing an STA service from multiple threads. The fact that it works should probably be considered luck more than anything. I agree with the original reporters statement that thread-safety is the users problem to work around.

One thing we could change in win32ole is the ability to specify that we want to access the service as MTA. This would allow MT programs to work at the extreme performance penalty that comes along with accessing a STA as MTA (100-1000x slower). It doesn't crash and for many COM services performance is not an issue.
__--------------------------------------
Bug #4405: WIN32OLE & Threads incompatible
http://redmine.ruby-lang.org/issues/4405

Author: Lars Christensen
Status: Open
Priority: Normal
Assignee: 
Category: ext
Target version: 
ruby -v: ruby 1.9.2p136 (2010-12-25) [i386-mingw32]


The WIN32OLE library does not work when using Ruby threads. It may raise exceptions such as this:

(druby://localhost:2002) threadsys.rb:7:in `connect': failed to parse display name of moniker `winmgmts://localhost/root/cimv2' (WIN32OLERuntimeError)

WIN32 OLE api's are not generally Thread safe, and it can be argued that it is the user's task to ensure that it is accessed only from one thread, or the main thread. However, there are some complications;

- Using WIN32OLE from DRb (DRb can not be used without Threads).
- Using WIN32OLE indirectly (e.g. through Sys::ProcTable).

My specific case was a DRb server that examined processes using Sys::ProcTable, which happen to use WIN32OLE. This causes an exception. Attached is a simple script that recreates the problem. Note that in this simple case, WIN32OLE is only invokes once, and only from one single thread (and it still throws the exception).

 

 

官方说这个bug已经修好了, 实际上还是存在, 这里给出一个暂时的解决方法:

 

 

require 'win32ole'

# Also possible using Daniel Berger's excellent windows-pr gem.
require 'Win32API'
CoInitialize = Win32API.new('ole32', 'CoInitialize', 'P', 'L')

threads = []
3.times do
  threads << Thread.new do
    begin
      CoInitialize.call( 0 )
      ie = WIN32OLE.new( "InternetExplorer.Application" )
      ie.visible = true
      ie.navigate( "http://google.com" )
      puts "OK"
    rescue Exception => e
      puts e.class
      puts e
      puts e.backtrace
    end
  end
end

threads.each {|t| t.join }
 

 

你可能感兴趣的:(thread)