Is the code "mutex.unlock if mutex.owned?" safe in Ruby? - ruby

The following simplified code (extracted from a rather big multi-threaded piece of software) very rarely results in a ThreadError: Attempt to unlock a mutex which is not locked:
begin
yield(mutex) if mutex.try_lock
ensure
mutex.unlock if mutex.owned?
end
on line 4.
That's in Ruby 2.1.5, which is EOF right now, but my understanding was that calling mutex.unlock is safe if current thread owns the mutex, which is being checked with mutex.owned?. Would I be wrong in this assumption?
I believe that yield(mutex) in line 2 does never attempt to unlock the yielded mutex.
I understand that using something like mutex.synchronize(&block) may be preferable instead - but I'm just wondering how the above snippet should behave. And if I'm missing something in my understanding.

Related

Need help understanding "DBWinMutex"

I am writing my own version of DebugView using this article: https://www.codeproject.com/Articles/23776/Mechanism-of-OutputDebugString as a starting point.
The code appears to work fine. However I do not understand the use of the named mutex "DBWinMutex".
This mutex is opened at the beginning of the code:
CComBSTR DBWinMutex = L"DBWinMutex";
HANDLE m_hDBWinMutex = ::OpenMutex(MUTEX_ALL_ACCESS,
FALSE,
DBWinMutex);
and not closed before the end of the program!?
I find this strange. I would think that the mutex would have to be locked and unlocked repeatedly so that OutputDebugString could write to the shared memory "DBWIN_BUFFER"?
However I am able to read OutputDebugString messages written by other programs so the mutex does not appear to lock "DBWIN_BUFFER" for writing.
Also I can also run DebugView in parallell with my DebugView implementation and they both can read OutputDebugString messages. So it seems the mutex does not grant exclusive read to "DBWIN_BUFFER" neither.
Using the MUTEX_ALL_ACCESS access as above means I have to run the program as administrator.
When I replace this with SYNCHRONIZE access the program appears to function exactly the same except that I do not have to run it as administrator.
Is this OK or may it cause some subtle bug?
Also I test the return from OpenMutex above and if it is null call CreateMutex.
As described in the article you linked to, DBWinMutex is used only by OutputDebugString() itself, to prevent multiple threads from writing to the output buffer at the same time. It is not necessary for a debug monitor to use DBWinMutex at all:
However, there is a mistake in the above image. It should look more like this instead:

Confusion about rubys IO#(read/write)_nonblock calls

I am currently doing the Ruby on the Web project for The Odin Project. The goal is to implement a very basic webserver that parses and responds to GET or POST requests.
My solution uses IO#gets and IO#read(maxlen) together with the Content-Length Header attribute to do the parsing.
Other solution use IO#read_nonblock. I googled for it, but was quite confused with the documentation for it. It's often mentioned together with Kernel#select, which didn't really help either.
Can someone explain to me what the nonblock calls do differently than the normal ones, how they avoid blocking the thread of execution, and how they play together with the Kernel#select method?
explain to me what the nonblock calls do differently than the normal ones
The crucial difference in behavior is when there is no data available to read at call time, but not at EOF:
read_nonblock() raises an exception kind of IO::WaitReadable
normal read(length) waits until length bytes are read (or EOF)
how they avoid blocking the thread of execution
According to the documentation, #read_nonblock is using the read(2) system call after O_NONBLOCK is set for the underlying file descriptor.
how they play together with the Kernel#select method?
There's also IO.select. We can use it in this case to wait for availability of input data, so that a subsequent read_nonblock() won't cause an error. This is especially useful if there are multiple input streams, where it is not known from which stream data will arrive next and for which read() would have to be called.
In a blocking write you wait until bytes got written to a file, on the other hand a nonblocking write exits immediately. It means, that you can continue to execute your program, while operating system asynchronously writes data to a file. Then, when you want to write again, you use select to see whether the file is ready to accept next write.

What happens if another process tries to write to a flock(2)'d file?

Specifically, if the following events take place in the given order:
Process 1 opens a file in append mode.
Process 2 opens the same file in append mode.
Process 2 gets an exclusive lock using flock(2) on the file descriptor.
Process 1 attempts to write to the file.
What happens?
Will the write return immediately with a code indicating failure? Will it hang until the lock is released, then write and return success? Does the behavior vary by kernel? It seems odd that the documentation doesn't cover this case.
(I could write a couple processes to test it on my system, but I don't know whether my test would be representative of the general case, and if anyone does know, I can anticipate this answer saving a lot of other people a lot of time.)
The write proceeds as normal. flock provides advisory locking. Locking a file exclusively only prevents others from getting a shared or exclusive lock on the same file. Calls other than flock are not affected.

Ruby's File.open and the need for f.close

It's common knowledge in most programming languages that the flow for working with files is open-use-close. Yet I saw many times in ruby codes unmatched File.open calls, and moreover I found this gem of knowledge in the ruby docs:
I/O streams are automatically closed when they are claimed by the garbage collector.
darkredandyellow friendly irc take on the issue:
[17:12] yes, and also, the number of file descriptors is usually limited by the OS
[17:29] I assume you can easily run out of available file descriptors before the garbage collector cleans up. in this case, you might want to use close them yourself. "claimed by the garbage collector." means that the GC acts at some point in the future. and it's expensive. a lot of reasons for explicitly closing files.
Do we need to explicitly close
If yes then why does the GC autoclose ?
If not then why the option?
I saw many times in ruby codes unmatched File.open calls
Can you give an example? I only ever see that in code written by newbies who lack the "common knowledge in most programming languages that the flow for working with files is open-use-close".
Experienced Rubyists either explicitly close their files, or, more idiomatically, use the block form of File.open, which automatically closes the file for you. Its implementation basically looks something like like this:
def File.open(*args, &block)
return open_with_block(*args, &block) if block_given?
open_without_block(*args)
end
def File.open_without_block(*args)
# do whatever ...
end
def File.open_with_block(*args)
yield f = open_without_block(*args)
ensure
f.close
end
Scripts are a special case. Scripts generally run so short, and use so few file descriptors that it simply doesn't make sense to close them, since the operating system will close them anyway when the script exits.
Do we need to explicitly close?
Yes.
If yes then why does the GC autoclose?
Because after it has collected the object, there is no way for you to close the file anymore, and thus you would leak file descriptors.
Note that it's not the garbage collector that closes the files. The garbage collector simply executes any finalizers for an object before it collects it. It just so happens that the File class defines a finalizer which closes the file.
If not then why the option?
Because wasted memory is cheap, but wasted file descriptors aren't. Therefore, it doesn't make sense to tie the lifetime of a file descriptor to the lifetime of some chunk of memory.
You simply cannot predict when the garbage collector will run. You cannot even predict if it will run at all: if you never run out of memory, the garbage collector will never run, therefore the finalizer will never run, therefore the file will never be closed.
You should always close file descriptors after use, that will also flush it. Often people use File.open or equivalent method with blocks to handle file descriptor lifetime. For example:
File.open('foo', 'w') do |f|
f.write "bar"
end
In that example the file is closed automatically.
According to http://ruby-doc.org/core-2.1.4/File.html#method-c-open
With no associated block, File.open is a synonym for ::new. If the
optional code block is given, it will be passed the opened file as an argument
and the File object will automatically be closed when the block
terminates. The value of the block will be returned from File.open.
Therefore, will automatically be closed when the block terminates :D
Yes
In case you don't, or if there is some other failure
See 2.
We can use the File.read() function to read the file in ruby.....
such as,
file_variable = File.read("filename.txt")
in this example file_variable can have the full value of that file....

ruby: How do i get the number of subprocess(fork) running

I want to limit the subprocesses count to 3. Once it hits 3 i wait until one of the processes stops and then execute a new one. I'm using Kernel.fork to start the process.
How do i get the number of running subprocesses? or is there a better way to do this?
A good question, but I don't think there's such a method in Ruby, at least not in the standard library. There's lots of gems out there....
This problem though sounds like a job for the Mutex class. Look up the section Condition Variables here on how to use Ruby's mutexes.
I usually have a Queue of tasks to be done, and then have a couple of threads consuming tasks until they receive an item indicating the end of work. There's an example in "Programming Ruby" under the Thread library. (I'm not sure if I should copy and paste the example to Stack Overflow - sorry)
My solution was to use trap("CLD"), to trap SIGCLD whenever a child process ended and decrease the counter (a global variable) of processes running.

Resources