Hi all,
Here''s my initial stab at a pure Ruby win32-thread library that
doesn''t
work at all. I''m not sure how to pass the start address of the
arguments
to the callback. I thought about Marshal, but you can''t marshal a proc.
BTW, the CreateThread method in windows-pr needs to be updated for this
to have any hope of success.
Any ideas?
Thanks,
Dan
# win32/thread.rb
require ''windows/thread''
require ''windows/synchronize''
require ''windows/error''
include Windows
module Win32
class Thread
include Windows::Thread
include Windows::Synchronize
include Windows::Error
extend Windows::Synchronize
class Error < StandardError; end
@@mutex = CreateMutex(nil, false, nil)
ABOVE_NORMAL = THREAD_PRIORITY_ABOVE_NORMAL
BELOW_NORMAL = THREAD_PRIORITY_BELOW_NORMAL
HIGHEST = THREAD_PRIORITY_HIGHEST
IDLE = THREAD_PRIORITY_IDLE
LOWEST = THREAD_PRIORITY_LOWEST
NORMAL = THREAD_PRIORITY_NORMAL
CRITICAL = THREAD_PRIORITY_TIME_CRITICAL
VERSION = ''0.1.0''
WinThreadFunc = API::Callback.new(''L'',
''L''){ |args|
block = args.pop
block.call(args)
ReleaseMutex(@@mutex)
}
attr_reader :thread_id
def initialize(*args, &block)
raise ArgumentError, ''block must be provided'' unless
block_given?
args.push(block)
thread_id = [0].pack(''L'')
dwArgs = nil # What should this be?
@thread = CreateThread(
nil, # Handle cannot be inherited
0, # Default stack size
WinThreadFunc, # Pointer to thread func
dwArgs, # Arguments passed to thread func
0, # Execute immediately, i.e. not suspended
thread_id # Stores the thread id
)
if @thread == 0
raise Error, get_last_error
end
@thread_id = thread_id.unpack(''L'')[0]
end
def join(limit = INFINITE)
limit = limit * 1000 unless limit == INFINITE
WaitForSingleObject(@thread, limit)
ReleaseMutex(@@mutex)
end
def terminate
exit_code = [0].pack(''L'')
return nil unless TerminateThread(@thread, exit_code)
end
def exit
ExitThread(0)
end
def priority
GetThreadPriority(@thread)
end
def priority=(value)
unless SetThreadPriority(@thread, value)
raise Error, get_last_error
end
end
end
end
if $0 == __FILE__
t = Win32::Thread.new(''a'', ''b''){ |x, y|
puts "Hello: #{x}, #{y}" }
t.join
end
Hi, ----- Original Message ----- From: "Daniel Berger" <djberg96 at gmail.com> To: "Development and ideas for win32utils projects" <win32utils-devel at rubyforge.org> Sent: Sunday, May 18, 2008 1:33 PM Subject: [Win32utils-devel] Pure win32-thread library?> Hi all, > > Here''s my initial stab at a pure Ruby win32-thread library that doesn''t > work at all. I''m not sure how to pass the start address of the arguments > to the callback. I thought about Marshal, but you can''t marshal a proc. > > BTW, the CreateThread method in windows-pr needs to be updated for this > to have any hope of success. > > Any ideas? >I think object_id and ObjectSpace._id2ref did the trick. After modifing CreateThread prototype as like this: API.new(''CreateThread'', ''PLKPLP'', ''L'') Here is a working code: # win32/thread.rb require ''windows/thread'' require ''windows/synchronize'' require ''windows/error'' include Windows module Win32 class Thread include Windows::Thread include Windows::Synchronize include Windows::Error extend Windows::Synchronize class Error < StandardError; end @@mutex = CreateMutex(nil, false, nil) ABOVE_NORMAL = THREAD_PRIORITY_ABOVE_NORMAL BELOW_NORMAL = THREAD_PRIORITY_BELOW_NORMAL HIGHEST = THREAD_PRIORITY_HIGHEST IDLE = THREAD_PRIORITY_IDLE LOWEST = THREAD_PRIORITY_LOWEST NORMAL = THREAD_PRIORITY_NORMAL CRITICAL = THREAD_PRIORITY_TIME_CRITICAL VERSION = ''0.1.0'' WinThreadFunc = API::Callback.new(''L'', ''L''){ |pargs| args = ObjectSpace._id2ref(pargs) block = args.pop block.call(args) ReleaseMutex(@@mutex) } attr_reader :thread_id def initialize(*args, &block) raise ArgumentError, ''block must be provided'' unless block_given? args.push(block) thread_id = [0].pack(''L'') dwArgs = args.object_id @thread = CreateThread( nil, # Handle cannot be inherited 0, # Default stack size WinThreadFunc, # Pointer to thread func dwArgs, # Arguments passed to thread func 0, # Execute immediately, i.e. not suspended thread_id # Stores the thread id ) if @thread == 0 raise Error, get_last_error end @thread_id = thread_id.unpack(''L'')[0] end def join(limit = INFINITE) limit = limit * 1000 unless limit == INFINITE WaitForSingleObject(@thread, limit) ReleaseMutex(@@mutex) end def terminate exit_code = [0].pack(''L'') return nil unless TerminateThread(@thread, exit_code) end def exit ExitThread(0) end def priority GetThreadPriority(@thread) end def priority=(value) unless SetThreadPriority(@thread, value) raise Error, get_last_error end end end end if $0 == __FILE__ t = Win32::Thread.new(''a'', ''b''){ |x, y| puts "Hello: #{x}, #{y}" } t.join end Regards, Park Heesob
Park Heesob wrote:> Hi, > ----- Original Message ----- > From: "Daniel Berger" <djberg96 at gmail.com> > To: "Development and ideas for win32utils projects" <win32utils-devel at rubyforge.org> > Sent: Sunday, May 18, 2008 1:33 PM > Subject: [Win32utils-devel] Pure win32-thread library? > > >> Hi all, >> >> Here''s my initial stab at a pure Ruby win32-thread library that doesn''t >> work at all. I''m not sure how to pass the start address of the arguments >> to the callback. I thought about Marshal, but you can''t marshal a proc. >> >> BTW, the CreateThread method in windows-pr needs to be updated for this >> to have any hope of success. >> >> Any ideas? >> > I think object_id and ObjectSpace._id2ref did the trick. > > After modifing CreateThread prototype as like this: > API.new(''CreateThread'', ''PLKPLP'', ''L'') > > Here is a working code:<snip> Yes, that works, thanks! Now I''m remembering this post from Wayne way back in 2004: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/123720 So, anyone up for some sort of GC work to prevent multiple native threads from crashing the interpreter? Regards, Dan