Forking and Processes
Using several Ruby processes is another strategy for attaining concurrency in Ruby. Use the fork() system call or its counterpart, Process. Fork, to accomplish this. Using a block is the simplest approach to using this function.
fork {
puts "Hello from the child process: #$$"
}
puts "Hello from the parent process: #$$"
You can also try this code with Online Ruby Compiler
Run Code
When used this way, the code that follows the block is continued by the initial Ruby process, and the new Ruby process executes the code within the block.
Fork behaves differently when called without a block. An integer that represents the process ID of the newly generated child process is returned by the fork function in the parent process.
The identical call to fork returns nil in the child process. Therefore, the above code may alternatively be expressed as follows:
pid = fork
if (pid)
puts "Hello from parent process: #$$"
puts "Created child process #{pid}"
else
puts Hello from child process: #$$"
end
You can also try this code with Online Ruby Compiler
Run Code
- Processes and threads differ greatly in that they do not share memory. When you use the fork command, a new Ruby process is created that is an identical copy of the parent process. However, any modifications it makes to the state of the Process (by modifying or creating objects) take place in its own address space. Both the parent process and the child process are unable to change the data structures that are observed by the other.
-
Use open and pass "|-" as the first argument if you require communication between your parent and child processes. The pipe to the freshly forked Ruby process is now open. The open call yields the corresponding block for both the parent and the child. The block in the child receives nothing. However, the block gets an IO object from the parent.
-
Data written by the child is returned when reading from this IO object. Additionally, information written to the IO object is now accessible for reading via the child's standard input.
For Example
open("|-", "r+") do |child|
if child
# This is the parent process
child.puts("Hello child") # Send to child
response = child.gets # Read from child
puts "Child said: #{response}"
else
# This is the child process
from_parent = gets # Read from parent
STDERR.puts "Parent said: #{from_parent}"
puts("Hi Mom!") # Send to parent
end
end
You can also try this code with Online Ruby Compiler
Run Code
Together with the fork or open methods, the Kernel.exec function is helpful. As we previously showed, you can send any command to the operating system shell using the system functions. Both of those techniques, however, are synchronous; they hold off on returning until the command has finished. Use a fork to establish a child process and then call exec in the child to perform the operating system command if you want to run it as a separate process. A call to exec creates a new process in lieu of the existing one and never returns. The arguments for system and exec are identical. It is handled as a shell command if there is just one. Any additional arguments become the "ARGV" for the executable if there are multiple arguments, and the first argument indicates the executable to invoke:
open("|-", "r") do |child|
if child
# This is the parent process
files = child.readlines # Read the output of our child
child.close
else
# This is the child process
exec("/bin/ls", "-l") # Run another executable
end
end
You can also try this code with Online Ruby Compiler
Run Code
The specifics of dealing with processes, a low-level programming activity, are outside the purview of this book. If you're interested in learning more, start using ri to read about the other Process module methods.
Trapping Signals
Asynchronous signals can be transmitted to an active process in most operating systems.
For instance, when a user presses Ctrl-C to cancel a program, this happens.
In response to Ctrl-C, the majority of shell applications transmit a signal called "SIGINT" (for interrupt). Additionally, the program is typically aborted as the default reaction to this signal. Ruby enables programs to define their signal handlers and "trap" signals. The Kernel.trap technique (or its synonym Signal.trap) is used to do this. If you don't want the user to be able to use Ctrl-C to cancel, for instance:
trap "SIGINT" {
puts "Ignoring SIGINT"
}
You can also try this code with Online Ruby Compiler
Run Code
-
You can pass a Proc object in place of a block when calling the trap method.
-
You can also supply the string "Disregard" as the second argument if all you want to do is silently ignore a signal. To make a signal behave as the OS would like it to, pass "DEFAULT" as the second argument.
- It can be helpful to define signal handlers in long-running applications like servers so that they can, for example, enter debugging mode, reread their configuration files, or dump use data to the log. For similar purposes, SIGUSR1 and SIGUSR2 are frequently used on Unix-like operating systems.
Terminating Programs
Several connected Kernel methods exist for ending programs or carrying out related tasks. The easiest to understand is the exit function. It causes the program to quit if the SystemExit exception is not handled.
However, END blocks and any shutdown handlers started using Kernel.at the exit are executed prior to the exit.
-
Use exit! to end the sentence instantly. The process exit code communicated to the operating system is specified by an integer input that is accepted by both methods. The terms Process.exit and Process.exit! are interchangeable for these two Kernel functions.
-
The exit function is called after the abort function prints the provided error message to the standard output stream (1).
-
In situations where the exception raised is anticipated to cause the application to crash, fail is merely a synonym for raise. Similar to abort, failure also results in a message being shown when the application ends.
For instance:
fail "Unknown option #{switch}"
You can also try this code with Online Ruby Compiler
Run Code
-
The warn function is related to abort and fail: it prints a warning message to standard error (unless warnings have been explicitly disabled with -W0). Note, however, that this function does not raise an exception or cause the program to exit.
- Sleep is another related function that does not cause the program to exit. Instead, it simply causes the program (or at least the current thread of the program) to pause for the specified number of seconds.
Frequently Asked Questions
What are ruby variables?
Data that can be used later in a program is stored in ruby variables. The names of each variable, which functions as memory, vary. There are four types of variables in Ruby i.e, local variable, class variable, instance variable, and global variable.
Explain in brief about the ruby module?
A Ruby module is a grouping of constants and methods. Module methods or instance methods can both be used in modules. Since they contain a collection of methods, class definitions, constants, and other modules, they are comparable to classes. They are described similarly to classes. Modules can not be used to construct objects or subclasses. There is no hierarchy of inheritance for modules. Modules primarily have two functions i.e. acting as namespace, they and they make it possible for classes to share functionality via the mixin facility.
What are ruby strings?
An arbitrarily ordered series of bytes that often represent characters can be stored and modified in a Ruby string object. They are produced by either using literals or String::new.
What Ruby does do when it concatenates strings. How many different ways are there to concatenate a string?
Ruby string concatenation refers to combining several strings into a single string. Concatenating strings allows you to connect multiple strings to create a single string. Ruby strings can be combined in one string using four different methods. They are using a plus sign, a single space, using << symbol, and using concat method.
In Ruby, how to make a new time instance?
With::new, a fresh instance of Time can be produced. This will consume time from your present system. Time can also be divided into units like a year, month, day, hour, minute, etc. You must wait at least a year before starting a new time instance. If only a year has passed, the system will set the time to 00:00:00 on January 1 of that year using the current time zone.
Conclusion
In this article, we discussed the functions that Ruby allows for interfacing with the operating system to run programs, fork new processes, handle signals, and so on. If you want to study more, don’t worry, coding ninjas have got you covered.
To study the ruby in detail, you can refer to these links:
Ruby
Documentation
Official Ruby FAQ
Ruby Koans
Refer to our Guided Path on Coding Ninjas Studio to upskill yourself in Data Structures and algorithms, Competitive Programming, JavaScript, System Design, Machine learning, and many more! If you want to test your competency in coding, you may check out the mock test series and participate in the contests hosted on Coding Ninjas Studio! But if you have just started your learning process and are looking for questions asked by tech giants like Amazon, Microsoft, Uber, etc., you must look at the problems, interview experiences, and interview bundle for placement preparations.
Nevertheless, you may consider our paid courses to give your career an edge over others!
Do upvote our blogs if you find them helpful and engaging!
Happy Learning!!