Haha, bro, nenu nee Telugu friend la, full vibe lo nee interview prep ki help
chestha! Congrats on the interview call from Krisemi Design
Technologies! Since they’ve asked you to prepare Linux system
programming (message queues, pipes, signals, processes, threads),
synchronization techniques, and ISRs (Interrupt Service Routines), I’ll
provide a beginner-friendly, interview-ready set of proper interview
questions for each topic, along with answers and tips to crack the
interview. I’ll tailor this to your level (based on our previous chats, where
you’re a beginner learning SHM, semaphores, mutexes, etc.) and ensure it’s
practical for a fresher or entry-level role. I’ll also include code snippets
where needed and focus on questions that test conceptual clarity, coding
ability, and problem-solving. Ready? Let’s nail this interview, nanna!
Interview Preparation Strategy
Why These Topics?: Linux system programming and ISRs are core to
embedded systems, OS development, and device drivers—likely
Krisemi’s focus. Synchronization is critical for safe IPC and threading.
Interview Level: Expect questions ranging from basic concepts
(e.g., “What’s a pipe?”) to coding problems (e.g., “Write a producer-
consumer using SHM”) and scenario-based (e.g., “How to handle
nested interrupts in ISRs?”).
Prep Tips:
Memorize key functions (use the cheatsheet from our last chat).
Practice explaining concepts in 1-2 minutes (e.g., “A semaphore
is…”).
Write code on a whiteboard or editor (e.g., SHM with semaphore).
Revise our previous discussions (SHM, semaphores, mutexes,
ISRs, processes).
Topic 1: Linux System Programming Concepts
This includes message queues, pipes, signals, processes, and threads.
I’ll break it down with questions, answers, and code examples where
relevant.
1.1 Message Queues
What Are They?: Message queues allow processes to send/receive
messages (data packets) in a queue, managed by the kernel. POSIX
(mq_open) or System V (msgget) APIs are used.
Interview Questions:
Q: What is a message queue, and how does it differ from
shared memory?
Answer: A message queue is an IPC mechanism where
processes send/receive structured messages via a kernel-
managed queue. Unlike shared memory, which shares a raw
memory region, message queues provide message boundaries
and priorities, but are slower due to kernel copying.
Tip: Mention POSIX vs. System V. Say: “POSIX mq_open is
modern; System V msgget is legacy.”
Example: “SHM is faster for large data; message queues are
better for small, structured messages.”
Q: Write a simple program to send and receive a message
using POSIX message queues.
Answer:
#include <mqueue.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main() {
mqd_t mq = mq_open("/myqueue", O_CREAT | O_RDWR, 0666, NULL);
if (mq == (mqd_t)-1) { perror("mq_open"); return 1; }
if (fork() == 0) { // Child (receiver)
char buf[100];
mq_receive(mq, buf, 100, NULL);
printf("Received: %s\n", buf);
mq_close(mq);
} else { // Parent (sender)
const char *msg = "Hello!";
mq_send(mq, msg, strlen(msg) + 1, 0);
wait(NULL);
mq_close(mq);
mq_unlink("/myqueue");
return 0;
Explanation: mq_open creates a queue, mq_send sends a
message, mq_receive reads it, mq_unlink cleans up.
Tip: Compile with -lrt: gcc -o mq mq.c -lrt. Explain: “This is
parent-child communication; for unrelated processes, use the
same queue name.”
Q: What are the advantages of message queues over pipes?
Answer: Message queues support message priorities, selective
receiving (by type in System V), and don’t require a parent-child
relationship. Pipes are simpler but FIFO-only and typically for
related processes.
Tip: Say: “Message queues are flexible for complex apps; pipes
are lightweight for simple data streams.”
Key Functions (POSIX):
mq_open(const char *name, int oflag, mode_t mode, struct mq_attr
*attr): Open/create queue.
mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned
int msg_prio): Send message.
mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int
*msg_prio): Receive message.
mq_close(mqd_t mqdes): Close queue.
mq_unlink(const char *name): Remove queue.
Header: <mqueue.h>
1.2 Pipes
What Are They?: Pipes are unidirectional data channels for IPC, typically
between parent-child processes. Named pipes (FIFOs) work for unrelated
processes.
Interview Questions:
Q: Explain pipes and named pipes. How do they differ?
Answer: A pipe is a kernel buffer for one-way data transfer,
created with pipe(), used between related processes (e.g.,
parent-child). Named pipes (FIFOs) are created with mkfifo, have
a filesystem name, and work for unrelated processes.
Tip: Say: “Pipes are anonymous; named pipes have a name
like /tmp/myfifo.”
Q: Write a program using a pipe to send data from parent to
child.
Answer:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
int main() {
int fd[2];
pipe(fd); // Create pipe
if (fork() == 0) { // Child
close(fd[1]); // Close write end
char buf[100];
read(fd[0], buf, 100);
printf("Child received: %s\n", buf);
close(fd[0]);
} else { // Parent
close(fd[0]); // Close read end
const char *msg = "Hello from parent!";
write(fd[1], msg, strlen(msg) + 1);
close(fd[1]);
wait(NULL);
return 0;
Explanation: pipe(fd) creates a pipe, fd[0] is read end, fd[1] is
write end. Parent writes, child reads.
Tip: Explain: “Close unused ends to avoid hangs. This is for
parent-child; named pipes use mkfifo.”
Q: When would you use a pipe instead of shared memory?
Answer: Use pipes for simple, one-way data streams between
related processes, as they’re easier to set up and don’t need
explicit sync. SHM is faster for large data or bidirectional sharing
but needs semaphores/mutexes.
Tip: Say: “Pipes are good for small, sequential data; SHM for
complex, shared structures.”
Key Functions:
pipe(int pipefd[2]): Create anonymous pipe.
read(int fd, void *buf, size_t count): Read from pipe.
write(int fd, const void *buf, size_t count): Write to pipe.
mkfifo(const char *pathname, mode_t mode): Create named pipe.
Headers: <unistd.h> (pipe, read, write), <sys/stat.h> (mkfifo)
1.3 Signals
What Are They?: Signals are software interrupts sent to a process to notify
events (e.g., SIGINT for Ctrl+C, SIGKILL to terminate).
Interview Questions:
Q: What are signals, and how are they handled in Linux?
Answer: Signals are notifications sent to a process for events
like termination (SIGTERM), interrupt (SIGINT), or errors
(SIGSEGV). They’re handled by:
Default action (e.g., terminate for SIGTERM).
Ignoring (using signal or sigaction).
Custom handler (signal handler function).
Tip: Say: “Use sigaction over signal for portability and control.”
Q: Write a program to handle SIGINT (Ctrl+C) with a custom
handler.
Answer:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void sigint_handler(int sig) {
printf("Caught SIGINT! Exiting gracefully.\n");
exit(0);
int main() {
struct sigaction sa;
sa.sa_handler = sigint_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGINT, &sa, NULL);
printf("Press Ctrl+C to test...\n");
while (1) pause(); // Wait for signals
return 0;
Explanation: sigaction sets sigint_handler for SIGINT. Handler
prints and exits.
Tip: Explain: “sigaction is preferred over signal for robust
handling. pause waits for signals.”
Q: How do you send a signal to a process?
Answer: Use kill(pid, sig) to send a signal to a process with PID
pid. Example: kill(1234, SIGTERM) sends SIGTERM to process
1234.
Tip: Mention: “kill -9 sends SIGKILL, which can’t be caught or
ignored.”
Key Functions:
sigaction(int signum, const struct sigaction *act, struct sigaction
*oldact): Set signal handler.
kill(pid_t pid, int sig): Send signal to process.
pause(void): Wait for signal.
Header: <signal.h>
1.4 Processes
What Are They?: Processes are independent programs with their own
memory space, managed by the OS.
Interview Questions:
Q: Explain fork() and exec(). How do they differ?
Answer: fork() creates a child process that’s a copy of the
parent, sharing code but with separate memory. exec() replaces
the current process’s image with a new program. fork() is for
creating processes; exec() is for running new programs.
Tip: Say: “fork returns 0 in child, child’s PID in parent.”
Q: Write a program using fork() to create a child that runs ‘ls’.
Answer:
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
int main() {
pid_t pid = fork();
if (pid == 0) { // Child
execl("/bin/ls", "ls", NULL);
perror("execl failed");
} else { // Parent
wait(NULL);
printf("Parent: Child finished\n");
return 0;
Explanation: fork creates a child, execl runs ls, wait ensures
parent waits.
Tip: Explain: “execl replaces the child’s program; wait prevents
zombies.”
Q: What’s a zombie process, and how do you prevent it?
Answer: A zombie is a terminated child process whose exit
status hasn’t been collected by the parent. Prevent it using wait()
or waitpid() in the parent.
Tip: Say: “Zombies waste resources; wait cleans them up.”
Key Functions:
fork(void): Create child process.
exec* (e.g., execl(const char *path, const char *arg, ...)): Run new
program.
wait(int *status): Wait for child.
Headers: <unistd.h> (fork, exec), <sys/wait.h> (wait)
1.5 Threads
What Are They?: Threads are lightweight execution units within a process,
sharing the same memory space.
Interview Questions:
Q: What’s the difference between a process and a thread?
Answer: A process has its own memory space and resources,
while threads share the same memory and resources within a
process. Processes are heavier; threads are lighter and faster for
parallel tasks.
Tip: Say: “Threads need sync (mutexes/semaphores) for shared
data.”
Q: Write a program to create two threads that increment a
shared counter safely.
Answer:
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t mutex;
int counter = 0;
void* thread_func(void* arg) {
for (int i = 0; i < 3; i++) {
pthread_mutex_lock(&mutex);
counter++;
printf("Thread %ld: Counter = %d\n", (long)arg, counter);
pthread_mutex_unlock(&mutex);
usleep(100000);
return NULL;
int main() {
pthread_mutex_init(&mutex, NULL);
pthread_t t1, t2;
pthread_create(&t1, NULL, thread_func, (void*)1);
pthread_create(&t2, NULL, thread_func, (void*)2);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("Final counter: %d\n", counter);
pthread_mutex_destroy(&mutex);
return 0;
Explanation: Two threads increment counter, synced with a
mutex.
Tip: Compile with -pthread: gcc -o thread thread.c -pthread. Say:
“Mutex prevents race conditions.”
Q: Why do threads need synchronization?
Answer: Threads share memory, so simultaneous access to
shared data (e.g., a counter) causes race conditions.
Synchronization (mutexes, semaphores) ensures safe access.
Tip: Use the above code as an example.
Key Functions:
pthread_create(pthread_t *thread, const pthread_attr_t *attr, void
*(*start_routine)(void*), void *arg): Create thread.
pthread_join(pthread_t thread, void **retval): Wait for thread.
Header: <pthread.h>
Topic 2: Synchronization Techniques
Synchronization prevents race conditions in SHM or threads. We covered
semaphores, mutexes, and briefly atomic operations.
Interview Questions:
Q: What are synchronization techniques, and why are they
needed?
Answer: Synchronization techniques (semaphores, mutexes,
condition variables, atomic operations) ensure safe access to
shared resources in multi-process or multi-threaded programs,
preventing race conditions where data gets corrupted due to
simultaneous access.
Tip: Say: “Example: Two threads incrementing a counter need a
mutex to avoid losing updates.”
Q: Explain semaphores and mutexes. How do they differ?
Answer: A semaphore is a counter for controlling access to
resources (binary for locking, counting for multiple resources). A
mutex is a lock with ownership, ensuring only one
thread/process accesses a resource. Semaphores are flexible for
resource counting; mutexes are simpler for exclusive locking.
Tip: Say: “Use semaphores for producer-consumer; mutexes for
simple critical sections.”
Q: Write a producer-consumer program using shared memory
and semaphores.
Answer:
#include <sys/mman.h>
#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#define SHM_NAME "/myshm"
#define BUFFER_SIZE 3
struct shm_data {
sem_t empty, full, mutex;
int buffer[BUFFER_SIZE];
int in, out;
};
int main() {
int fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
ftruncate(fd, sizeof(struct shm_data));
struct shm_data *data = mmap(NULL, sizeof(struct shm_data),
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
sem_init(&data->empty, 1, BUFFER_SIZE);
sem_init(&data->full, 1, 0);
sem_init(&data->mutex, 1, 1);
data->in = data->out = 0;
if (fork() == 0) { // Consumer
for (int i = 0; i < 5; i++) {
sem_wait(&data->full);
sem_wait(&data->mutex);
printf("Consumer: Got %d\n", data->buffer[data->out]);
data->out = (data->out + 1) % BUFFER_SIZE;
sem_post(&data->mutex);
sem_post(&data->empty);
usleep(100000);
munmap(data, sizeof(struct shm_data));
} else { // Producer
for (int i = 0; i < 5; i++) {
sem_wait(&data->empty);
sem_wait(&data->mutex);
data->buffer[data->in] = i + 1;
printf("Producer: Put %d\n", data->buffer[data->in]);
data->in = (data->in + 1) % BUFFER_SIZE;
sem_post(&data->mutex);
sem_post(&data->full);
usleep(100000);
wait(NULL);
sem_destroy(&data->empty);
sem_destroy(&data->full);
sem_destroy(&data->mutex);
munmap(data, sizeof(struct shm_data));
shm_unlink(SHM_NAME);
}
return 0;
Explanation: Uses SHM with three semaphores: empty (buffer
slots), full (items), mutex (buffer access).
Tip: Compile with -pthread -lrt. Explain: “This prevents buffer
overflow/underflow and race conditions.”
Q: What’s a race condition, and how do you prevent it?
Answer: A race condition occurs when multiple
processes/threads access shared data simultaneously, causing
corruption (e.g., two threads increment a counter, losing an
update). Prevent it with mutexes, semaphores, or atomic
operations.
Tip: Use the thread counter code above as an example.
Key Functions (from cheatsheet):
Semaphores: sem_init, sem_wait, sem_post, sem_destroy, sem_open,
sem_close, sem_unlink (<semaphore.h>).
Mutexes: pthread_mutex_init, pthread_mutex_lock,
pthread_mutex_unlock, pthread_mutexattr_setpshared (<pthread.h>).
Topic 3: Interrupt Service Routines (ISRs)
What Are They?: ISRs are functions executed in response to
hardware/software interrupts, critical for embedded systems.
Interview Questions:
Q: What is an ISR, and how is it different from a normal
function?
Answer: An ISR is a special function triggered by an interrupt
(e.g., timer, keyboard). Unlike normal functions, ISRs run in
interrupt context, are non-blocking, have no return
value/parameters, and must be fast to avoid delaying other
interrupts.
Tip: Say: “ISRs use the Interrupt Vector Table to map interrupts
to handlers.”
Q: Explain how an ISR is called when an interrupt occurs.
Answer: When an interrupt occurs:
Hardware sends a signal to the CPU.
CPU saves context (registers, PC).
CPU looks up the ISR address in the Interrupt Vector Table
(IVT).
ISR executes, clears the interrupt, and returns.
CPU restores context and resumes the program.
Tip: Say: “The OS sets up the IVT during boot, e.g., using
request_irq in Linux.”
Q: Write a pseudo-code ISR for a timer interrupt.
Answer:
volatile int tick_count = 0;
void timer_isr(void) {
tick_count++; // Increment tick
clear_timer_interrupt(); // Hardware-specific
acknowledge_interrupt(); // Signal completion
Explanation: Increments a counter, clears the interrupt to
prevent re-triggering.
Tip: Say: “Use volatile for shared data to prevent compiler
optimization.”
Q: How do you ensure an ISR is safe?
Answer: To make an ISR safe:
Keep it short and fast.
Avoid blocking calls (e.g., sleep, I/O).
Use volatile for shared data.
Don’t use mutexes/semaphores (defer to threads).
Clear interrupt flags to avoid re-triggering.
Tip: Say: “Complex work is deferred to a bottom-half (e.g.,
softIRQ in Linux).”
Q: How do you handle shared data between an ISR and a
thread?
Answer:
#include <pthread.h>
volatile int data_ready = 0;
pthread_mutex_t mutex;
void data_isr(void) {
data_ready = 1; // Set flag
clear_interrupt();
void* thread_func(void* arg) {
while (1) {
pthread_mutex_lock(&mutex);
if (data_ready) {
printf("Thread: Data processed\n");
data_ready = 0;
pthread_mutex_unlock(&mutex);
usleep(100000);
return NULL;
}
Explanation: ISR sets a volatile flag; thread processes it with a
mutex.
Tip: Say: “Avoid locks in ISRs; use flags and let threads handle
sync.”
Key Context:
request_irq (Linux kernel, <linux/interrupt.h>): Registers ISR.
Interview Tip: Focus on ISR characteristics (fast, non-blocking) and
sync with threads.
Mock Interview Questions (Mix of All Topics)
Q: Design a system where two processes communicate using
shared memory and semaphores.
Answer: Use the producer-consumer code above. Explain: “SHM
for the buffer, semaphores (empty, full, mutex) for sync.”
Tip: Draw: Process A → SHM → Process B, mention shm_open,
mmap.
Q: How would you handle a scenario where a process needs to
wait for a specific signal?
Answer: Use pause() or sigsuspend with a signal handler:
#include <signal.h>
void sigusr1_handler(int sig) { printf("Got SIGUSR1\n"); }
int main() {
signal(SIGUSR1, sigusr1_handler);
printf("Waiting for SIGUSR1...\n");
pause();
return 0;
Tip: Say: “sigaction is better for robust handling.”
Q: Compare pipes, message queues, and shared memory for
IPC.
Answer:
Pipes: Simple, one-way, for related processes, no sync
needed.
Message Queues: Structured messages, priorities, for
unrelated processes, kernel-managed.
SHM: Fastest, raw memory, needs sync
(semaphores/mutexes).
Tip: Say: “Choose based on data size and sync needs.”
Q: What happens if you don’t synchronize threads accessing a
shared variable?
Answer: Race conditions occur, leading to data corruption.
Example: Two threads increment counter, but one update is lost
without a mutex.
Tip: Refer to the thread counter code.
Q: How do you debug an ISR that’s not working?
Answer:
Check if the interrupt is enabled (hardware/OS setup).
Verify IVT mapping (request_irq in Linux).
Ensure interrupt flag is cleared.
Use logs (e.g., printk in kernel) or debuggers.
Tip: Say: “Avoid complex logic in ISRs to simplify debugging.”
Interview Success Plan
Memorize Key Functions (Use Cheatsheet):
SHM: shm_open, mmap, ftruncate.
Semaphores: sem_init, sem_wait, sem_post.
Mutexes: pthread_mutex_init, pthread_mutex_lock.
Threads: pthread_create, pthread_join.
Signals: sigaction, kill.
Pipes: pipe, read, write.
Message Queues: mq_open, mq_send, mq_receive.
Practice Coding:
Run the programs above:
Pipe (parent-child).
Message queue (send/receive).
SHM producer-consumer.
Thread counter.
Signal handler.
Compile: gcc -o program program.c -pthread -lrt.
Write each on a whiteboard in 5-7 minutes.
Explain Concepts:
For each topic, prepare a 1-2 minute explanation:
Message Queue: “Kernel-managed queue for structured
messages.”
Pipe: “One-way data channel, simple for related
processes.”
Signal: “Notification for events, handled by custom
functions.”
Process: “Independent program with own memory.”
Thread: “Lightweight, shares memory, needs sync.”
Semaphore: “Counter for sync, binary or counting.”
Mutex: “Lock with ownership.”
ISR: “Fast handler for interrupts, non-blocking.”
Scenario Prep:
Practice answering “Design a system…” questions (e.g.,
producer-consumer).
Draw diagrams: SHM (Process A → SHM → Process B), ISR flow
(Interrupt → IVT → ISR).
Revise Previous Chats:
SHM: Normal, semaphore, mutex programs (last chat).
ISR: How ISRs are called, polling vs. ISR.
Processes: FCFS, Round-Robin, fork/wait.
Cheatsheet: Use for function prototypes/headers.
Mock Interview:
Ask a friend to ask 5 random questions from above.
Time yourself: 2 minutes for theory, 5-7 minutes for code.
Final Clarity, Bro
Bro, ippudu Krisemi Design Technologies interview ki full ready
anukuntunna!
Questions: Covered message queues, pipes, signals, processes,
threads, sync, and ISRs with answers and code.
Cheatsheet: Use it for functions, headers, and examples.
Plan: Memorize, code, explain, and practice scenarios.
Quick Tips:
Be confident: Say “I’ll explain with an example” and use
code/diagrams.
If stuck: Say “Let me think…” and walk through the problem (e.g., SHM
steps).
Revise our SHM programs and ISR explanations—they’re likely to
appear.
Inka doubt unte (e.g., “Producer-consumer ela explain cheyali?” or specific
question prep), cheppu, nanna! Telugu vibe lo, full support istha! What’s
next? Want to practice specific questions or need a mock interview script?
All the best for cracking the interview!