GATE 2026 OS PYQs | PROCESSES AND THREADS (JavaScript)
Learn GATE 2026 OS PYQs | PROCESSES AND THREADS (JavaScript) step by step with clear examples and exercises.
Title: GATE 2026 OS PYQs | PROCESSES AND THREADS (JavaScript)
Why This Matters
In the realm of operating systems, understanding processes and threads is crucial for managing resources efficiently, ensuring smooth multitasking, and optimizing system performance. The Graduate Aptitude Test in Engineering (GATE) assesses your knowledge in these areas, making it essential to master processes and threads, especially in JavaScript. This lesson will delve into the practical aspects of JavaScript processes and threads, focusing on real-world scenarios, common mistakes, and practice questions.
Prerequisites
To fully grasp this topic, you should have a solid understanding of:
- Basic JavaScript concepts (variables, functions, loops, arrays)
- Event-driven programming model in JavaScript
- Asynchronous JavaScript (promises, async/await)
- Node.js and its event loop
- Understanding of Operating System concepts such as processes, threads, synchronization, and concurrency.
- Familiarity with system calls and APIs related to process management and inter-process communication.
- Knowledge of JavaScript modules and their usage in Node.js.
- Basic understanding of event handling and callbacks in JavaScript.
- Understanding of asynchronous I/O operations in Node.js.
- Familiarity with error handling techniques in JavaScript, including try-catch blocks and promise rejection handling.
Core Concept
Processes
In the context of operating systems, a process is an instance of a program that is being executed by the system. Each process has its own memory space, allowing it to run independently without interfering with other processes. In JavaScript, there are no native processes as in other languages like C or Python. However, Node.js creates multiple worker processes using the child_process module to execute JavaScript code concurrently.
Creating a Worker Process
const { fork } = require('child_process');
// Create a new worker process
const worker = fork('./worker.js');
// Listen for messages from the worker process
worker.on('message', (msg) => {
console.log(`Received message from worker: ${msg}`);
});
In this example, we create a new worker process using the fork() function and listen for messages it sends back to the parent process. The worker process runs in a separate memory space but shares the same Node.js environment, allowing it to access the same modules and variables as the parent process.
Communicating with Worker Processes
Worker processes can communicate with their parent by sending messages using the send() method:
worker.send({ hello: 'world' });
The parent process can also send messages to the worker:
worker.send('some data');
Process Management
Node.js provides several methods for managing child processes, such as kill(), on('exit'), and on('error'). These methods allow you to terminate a worker process, handle its exit event, or listen for errors that occur within the worker process.
Threads
A thread is a smaller sequence of instructions that can run concurrently within a single process. Unlike processes, threads share the same memory space, which allows them to communicate more efficiently. JavaScript also does not support native threads due to its single-threaded nature. However, asynchronous functions and event loop help achieve concurrency in JavaScript by allowing the browser or Node.js to switch between tasks non-blockingly.
Asynchronous Functions
Asynchronous functions allow JavaScript to execute multiple tasks concurrently without blocking the main thread. This is achieved using callbacks, promises, and async/await syntax.
// Callback example
function fetchData(callback) {
setTimeout(() => {
callback('Data fetched');
}, 2000);
}
fetchData((data) => console.log(data));
In this example, the fetchData() function uses a callback to pass data back to the calling function once it has been fetched asynchronously.
Event Loop and Callbacks
The event loop is a key component of Node.js that allows it to handle concurrent tasks efficiently. When an asynchronous task is completed, its callback is added to the event queue, where the event loop can execute it when the main thread is idle.
// Event loop example
setTimeout(() => {
console.log('Settimeout executed');
}, 0);
console.log('Main thread executing');
In this example, the setTimeout() function schedules a callback to be executed after a short delay, but the main thread continues executing before the callback is added to the event queue and run.
Worked Example
Let's create a simple Node.js script using child processes to demonstrate process creation:
const { fork } = require('child_process');
// Create a new worker process
const worker1 = fork('./worker1.js');
const worker2 = fork('./worker2.js');
let sum = 0;
// Listen for messages from the worker processes and calculate their sum
worker1.on('message', (msg) => {
sum += msg;
});
worker2.on('message', (msg) => {
sum += msg;
});
// Once both workers have sent their results, print the total sum
worker1.on('exit', () => {
worker2.send('done');
});
worker2.on('exit', () => {
console.log(`Sum: ${sum}`);
});
In this example, we create two worker processes that perform separate calculations and send their results back to the parent process. The parent process calculates the total sum once both workers have completed their tasks.
Common Mistakes
- Not handling errors properly: Forgetting to handle errors in child processes can lead to unhandled exceptions that crash your application.
- Sharing data improperly: Sharing data between parent and worker processes requires careful synchronization to avoid race conditions and inconsistencies.
- Blocking the event loop: Using synchronous functions or excessive I/O operations in a worker process can block the event loop, causing other tasks to be delayed.
- Ignoring the main thread: Overusing worker processes can lead to excessive resource consumption and poor performance, as each worker process requires its own memory space and CPU time.
- Not using async/await correctly: Misusing async/await functions can create callback hell or lead to unintended blocking of the event loop.
- Not properly terminating worker processes: Failing to terminate worker processes when they are no longer needed can cause memory leaks and performance issues.
- Incorrectly passing data between parent and worker processes: Improper serialization or deserialization of data can lead to errors or security vulnerabilities.
- Not considering process limits: Exceeding the number of allowed processes can result in errors or system instability.
- Ignoring process environment variables: Failing to account for process environment variables can cause issues when running scripts in different environments.
- Not properly handling signals and events: Improper handling of signals and events can lead to unhandled exceptions, crashes, or security vulnerabilities.
Practice Questions
- Write a Node.js script that creates two worker processes, each performing a separate calculation, and returns their sum as the result.
- Implement an asynchronous function that fetches data from an API using
fetch()and processes it before returning the result. How would you ensure this function doesn't block the event loop? - Given the following code snippet, explain what happens when the script is run:
const fs = require('fs');
fs.readFile('./file.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
console.log("Script started");
FAQ
How does Node.js manage concurrency without threads?
Node.js uses an event loop and non-blocking I/O operations to achieve concurrency. When a task is blocked (e.g., waiting for user input or reading from a file), the event loop can switch to another task that is not blocked, allowing the application to handle multiple tasks concurrently without threads.
Can I create multiple threads in JavaScript?
JavaScript does not support native threads due to its single-threaded nature. However, asynchronous functions and event loop help achieve concurrency in JavaScript by allowing the browser or Node.js to switch between tasks non-blockingly.
What are the benefits of using worker processes in Node.js?
Worker processes allow you to offload CPU-intensive tasks from the main thread, improving overall performance and responsiveness. They also enable parallelism by executing multiple tasks concurrently in separate memory spaces.
How can I handle errors in child processes effectively?
To handle errors in child processes effectively, you should:
- Use try-catch blocks to catch exceptions within the worker process.
- Listen for 'error' events on the worker process to handle unhandled exceptions.
- Implement proper error handling and logging mechanisms to identify and address issues quickly.
- Ensure that all functions called within the worker process also handle errors appropriately.
- Use promise-based APIs where possible to simplify error handling.
- Consider using a library like
cross-spawnfor managing child processes, which provides more robust error handling features.