From: Bob Gustafson Date: 2002-03-29T15:39:41+09:00 Subject: Re: Threads in Iterators Whether you need a mutex or not depends on two things: 1) Do you have multiple processors? If you have a single processor, then by definition, everything happens in serial. This is modified a bit because a single processor can be interrupted and a different thread or process started after the interruption (by the scheduler). This can cause grief even though you have a single processor. With a single processor you can live without mutexes, but you need to have a very detailed knowledge of your operating system ideosyncracies and which operations are atomic and which are not (which was the question you asked). 2) Are some of the possible multiple parallel happenings going to modify 'the same' value? If each of the multiple parallel happenings only affects its own state variables and there are no 'shared' state variables, then you don't need a mutex around the code. However, if some (or all) of the multiple parallel happenings changes a shared variable (perhaps on disk, or in (shared) memory), then a mutex needs to be placed around this shared variable modification code in all of the multiple parallel happenings, so that access to this shared variable is serialized properly. A very interesting situation happens when you have multiple parallel processes writing out to a monitor window. In the general case, you will have pieces of lines from one process interspersed with line pieces from other processes. Very confusing to read, but all of the processes are operating 'correctly'. To make the monitor output easier to read, you need another process which will buffer the lines from each of the other processes and then when it sees a carriage return, it will output the whole line to the monitor window - perhaps with a label at the front to identify the process. The actual writing to the window is done by a single process and is serial. The updating of the line buffers within this monitor output process is a bit more tricky and needs some mutex magic. Anyway, this is my understanding of the problem. Sorry I could not offer any info on which operations are atomic and which are not. BobG >> If you are concerned about this, then use a mutex around code that might >> corrupt your data: >> >> m = Mutex.new >> arr.each do |val| >> @mutex.synchronize do >> vals << val >> end >> end >> >> I think appending onto vals like this should be an atomic operation (so >> the mutex isn't necessary), but if you had a non-atomic operation, then >> you would definitely need a mutex. > >How do I know what operations are atomic operations in ruby? I guess I should >assume, unless explicitly specified, that all operations in ruby are not >atomic. >Actually my main concern is the yield below: > >> def arr.each >> 0.upto(length-1) do |i| >> Thread.new(self[i]) {|val| >> sleep(rand .1) >> yield val >> } >> end >> end > >I'm not so concerned about the order of the yields--obviously, that will be >undeterministic. What I'm concerned about is that with arr.each, is it >possible >that the yield will happen at the same time as another yield, messing >things up >somehow? Or, are yields atomic as well? The reason I'm doing this is >that each >loop in the iterator might (can't predict) take a very long or short time to >finish and I want to process things as soon as they become available (for >example if the first iteration has a very long process and the second has >a very >short process, then I want to thread both and have the first block be from the >second short process's yield). Perhaps, adding a mutex around the yield? > >Thanks, > >Norman