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