b r a y d e n . o r g / Software

/ WebHome / LanguagePages / RubyLanguage / RubyNotes

This Web


WebHome  
Topic List  
Web Statistics 

All Webs


Books
Main
Random
Software
TWiki  

brayden.org


Home
Monthly Digest
Today's Links
Resumé
Reading List
Books RSS
Random RSS
Software RSS

Other


Dale's Blog

currently-reading
TextDrive

From comp.lang.ruby

See also: RubyLanguage


2003/1/12

Hi --

I seem to keep coming up with Ruby projects that run aground on the matter of thread safety. The most recent was the little Object#stretch thing which extended objects module-wise for the duration of a block. The larger earlier project that ran into the same thing was Ruby Behaviors, which provides a way to do block-scoped (but not thread safe) changes to core classes and modules.

I've been trying to think through the matter of thread safety systematically. I've started to wonder whether there are different kinds of thread safety, like there are different kinds of infinities....

I'm not trying to argue a lax position about thread safety. I'm just trying to understand it as deeply as I can. The difference between Ruby code that does something and Ruby code that does something thread-safely seems so vast; one essentially loses out on all the conciseness of the language. At least that's my impression. Mind you, I've done very little thread programming, which may explain why I find the "it's not thread safe" semi-brick wall sort of exasperating, and also may explain any deficiencies in my grasp of the technicalities.

Anyway, here's a snapshot of my current possibly rambling thoughts -- some notes to myself, neatened up a bit. I'd be interested in hearing what people think.

* * *

Ruby is already not thread-safe, in the sense that if you don't know whether other threads are running, then weird things can always happen. For example, if you do this:

obj.each { |e| puts e.upcase }

it's possible that obj.upcase will be undefined or redefined between iterations, if you're going on the assumption that other threads might be running and that you don't know what they will be doing.

Therefore, lack of thread safety (of this kind) is something we live with. There may be a rogue thread out there somewhere (we assume).

So... what exactly does it mean to say that a particular practice is not thread safe? I guess it means that the practice itself is the rogue thread.

But if we're planning around rogue threads -- if we always act as if they might be there -- then theoretically shouldn't it be OK if they are there? Or is this one of those game theory (at least the popularized versions) questions, where A and B have to act together to succeed but don't know what the other is doing?

Let's take Ruby Behaviors as an example. Let's say you change the behavior of Array#join for the duration of a block:

b = Behavior.new("MyBehavior") b.adopt do # ... stuff ... end

The problem here is that some other thread might be using Array#join, and might expect it to work in the normal way.

OK, that's bad. But the question is... is it worse than the regular conditions under which Ruby code runs? If my premise is right, every call to Array#join already runs the risk of taking place after some other thread has done something weird. So what's the difference?

That's what I'm trying to figure out. Is it just quantity (i.e., increasing the likelihood of "something weird" going on in a distant thread)? Or are the baseline conditions of Ruby actually less fragile than I'm suggesting?

Of course the sensible thing to do is to declare all modifications to core functionality to be dangerous and avoid it. That's probably reasonable... but I just can't get away from the thought that the changeable nature of Ruby objects, including core classes, is something with depths that can be explored, rather than one of these "enough rope to hang yourself" things.

Is it enough to document that something isn't thread-safe, and let people decide whether or not to use it? Is there in fact such a thing as absolutely knowing that multiple threads will not be running?

This is all very fragmentary but I'm just trying to stir up and (eventually :-) clarify my thoughts on the subject.

David

David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web:  http://pirate.shu.edu/~blackdav

2002/12/10

Nice summary query in mySql

On Sun, 8 Dec 2002 18:04:54 +0200, "The Dude" <noreply@sourceforge.net> wrote:

Is there a way to get these 3 results by making just one
mysql query instead of these 3 queries?


$res = mysql_query("select count(user_id) from {$tables['users']}");
$arr = mysql_fetch_array($res);
$stats['usernum'] = $arr[0]; // total number of users
mysql_free_result($res);

$res = mysql_query("select count(user_id) from {$tables['users']} where
user_active='".USER_ACTIVE."'");
$arr = mysql_fetch_array($res);
$stats['useractive'] = $arr[0]; // number of active users
mysql_free_result($res);

$res = mysql_query("select count(user_id) from {$tables['users']} where
user_active='".USER_DISABLED."'");
$arr = mysql_fetch_array($res);
$stats['userdisabled'] = $arr[0]; // number of disabled users
mysql_free_result($res);

mysql> select * from user;
+---------+---------------+
| user_id | user_active   |
+---------+---------------+
|       1 | USER_ACTIVE   |
|       2 | USER_ACTIVE   |
|       3 | USER_DISABLED |
|       4 | USER_DISABLED |
|       5 | USER_DISABLED |
+---------+---------------+
5 rows in set (0.01 sec)

mysql> SELECT SUM(1) AS total_users,
    ->        SUM(CASE
    ->            WHEN user_active = 'USER_ACTIVE' THEN 1
    ->            ELSE 0
    ->            END) AS active_users,
    ->        SUM(CASE
    ->            WHEN user_active = 'USER_DISABLED' THEN 1
    ->            ELSE 0
    ->            END) AS disabled_users
    -> FROM   user
    -> ;
+-------------+--------------+----------------+
| total_users | active_users | disabled_users |
+-------------+--------------+----------------+
|           5 |            2 |              3 |
+-------------+--------------+----------------+
1 row in set (0.01 sec)

-- 
Andy Hassall (andy@andyh.org) icq(5747695) http://www.andyh.org
http://www.andyhsoftware.co.uk/space | disk usage analysis tool
----

2002/12/07

Compare raise and throw

Can some[one] briefly compare raise and throw for me? Thx!

"raise" raises an error/exception (whatever you want to call it). This exception - which is an object - is "rescued" later and some error-handling code performed.

"throw" throws a symbol out into the wilderness, hoping that someone will "catch" it.

There are distinct similarities in their operation, the most important one being that they can jump the boundaries of several method invocations (stack frames) at once. There are probably differences too, but to me, the real difference is of intent. "raise/rescue/ensure" is for exception handling, and "throw/catch" is for signalling - generally signalling that something has finished early and we can quite the whole operation altogether.

The other difference is that I've never used throw/catch, and consider it a bit dodgy. raise/resuce/ensure, OTOH, I use all the time.

See Pickaxe for more information.

Gavin

Matz on top-level functions

Hi,

In message "(Top-level "functions" == private methods).is_evil?" on 02/12/07, Mauricio Fernández writes:

|I was recently quite surprised to find that top-level "functions" are |actually private instance methods of Object, for I really expected them to be |singleton methods (see http://www.ruby-talk.com/blade/57607). This seemed |"unclean" to me from the beginning, because I saw that this would mean |that all Ruby objects were getting strange private methods, but OTOH |nothing seemed to be wrong as the public interface was not modified, |and these methods were shadowed by new ones.

"functions" cannot be singleton methods of the top-level object. If they were singleton methods, how do you "print" inside of a method, for example?

They are evil, as you said. But I have no better alternative idea. Any other "function" ideas make Ruby too complex. I had to compromise.

matz.


2002/11/22

Dynamic class creation

I have a system at the moment where I create 'things' based on a base class SceneObject?, these 'things' have a Proc associated with them that gets called to produce a different representation of the 'thing' (in my case data to be passed to a 3D renderer). At the moment it all works like this...
class SceneObject
  def initialize(&generate)
    @generate = generate
  end
  def render
    self.instance_eval(&@generate)
  end
end

class MyObject < SceneObject
  def initialize
    super() do
      # Render some objects
    end
  end
end

a = MyObject.new
a.render

This all works, but I'd like to 'hide' the class definition stuff, the reason being that the data files passed through this system will be defined outside, and don't need to look like Ruby code, they 'use' Ruby code to do the procedural stuff, but other than that I want them to appear as simple as possible, so hiding classes, inheritance, initialisation functions etc. would be a big benefit. Ideally I'd like to do something like this, but can't...

def defineClass(name,&generate)
  eval <<-"end_eval"
    class #{name} < SceneObject
      def initialize
        super(&#{generate})
      end
    end
  end_eval
end

Then in my data files use this function like so...

defineClass("MyObject") do
  # Render some objects
end

a = MyObject.new
a.render

Can anyone offer any advice on how to achieve something like this?

Cheers

PaulG?


This is with ruby 1.7
pigeon% cat b.rb
#!./ruby

class SceneObject
   def initialize(&generate)
      @generate = generate
   end
   alias init initialize

   def render
      instance_eval(&@generate)
   end
end

def defineClass(name, &block)
   Object.const_set(name, Class.new(SceneObject)).instance_eval do
      define_method(:initialize) { init(&block) }
   end
end

defineClass("MyObject") do
   puts "render some object"
end

a = MyObject.new
a.render
pigeon%
 
pigeon% b.rb
render some object
pigeon% 

Guy Decoux


2002/11/19

Generators - Some Ideas

I've been looking through the generator threads in the archive, and they all seem to centre around the problem of converting an internal iterator to an external iterator. This would be a wonderful thing, I admit, but so far there's been no time and space efficient way to do it (as far as I've seen, you either need to dump the enumerable to an array, or use call/cc).

Leaving aside the general problem for the minute, it might be useful to see where we can efficiently write

  g = <nop>SimpleGenerator.new(a) # should be space-efficient
  i = g.next # should be O(1) and cheap

and where the generator iterates over the sequence nondestructively, so that it is threadsafe. One could use g.val rather than g.next, depending on how you think of it.

SimpleGenerator.new would most likely need to be a factory that instantiated more specific per-type generators. Some easy examples for generator-generating objects:

Another nice possibility is built-in support for parallel iteration on generatable structures:

 gen = <nop>SimpleGenerator.new (a,b,c,d) {|a,b,c,d| [[a,b],c+d]]}

where gen.next returns [a.next,b.next,c.next,d.next] if no block is given, and passes it into the block if it is. The arguments could be automatically converted to generators if they were of some generatable type, which allows freely mixing generatables and anything else responding to .next. Of course, this runs into the same problems as zip does when one of the generators runs out before the others do.

Further ideas:

Composition:

Filtering: have an optional filter function (via .filter), so that next calls itself repeatedly until the filter succeeds.

#each: converting an external to an internal iterator is fairly trivial, though there would, of course, be issues with circular and infinite generators.

Implementation shouldn't be too hard - I'll put something up on the wiki when I get a free moment. Comments? Has anyone done something like this already?

martin


Passing block to recusively-called function

Hello,

I defined an iterator and tried using it and got a "no block given" error. I don’t understand why I got this error because I did define a block. The yield statement is in the replace_text function and the iterator is called in the remove_destroy function.

Thank you,

Brian Takita

def replace_text(dir_name = '.')
   #raise "No Block" unless block_given?
   d = Dir.new(dir_name)
   
   d.each{|x|
      if x == '.' || x == '..'
         next
      end
      
      if FileTest.directory?(x)
         puts dir_name + '--' + x
         
         Dir.chdir(x)
         replace_text()
         Dir.chdir('..')
      else
         if x =~ /(\.php)/
            puts dir_name + '->' + x
            f = File.new(x)
            
            content = ''
            f.each_line { |line|
               yield line
               content += line
            }
            f.close
            
            f = File.new(dir_name + '/' +x, 'w+')
            f.write(content)
            f.close
         end
      end
   }
   d.close
end
 
def remove_destroy()
   replace_text { |line|
      if line =~ /.*->destroy\(\).*\n/
         line = ""
      end
   }
end

remove_destroy()


Thank you for your help Guy.

I solved the recursion problem by replacing

replace_text()

With

replace_text() { yield }

Sincerely, Brian Takita

-- DaleBrayden - 19 Nov 2002

 
 
Current Rev: r1.7 - 25 Jun 2003 - 05:54 GMT - DaleBrayden, Revision History:Diffs | r1.7 | > | r1.6 | > | r1.5
© 2003-2011 by the contributing authors.