0% found this document useful (0 votes)
78 views14 pages

Solutions 2

This document contains solutions to exercises on system programming in Linux using C++. It includes examples of multithreading using mutexes, shared memory using mmap, inter-process communication using pipes, and spawning child processes using fork. The exercises cover concepts such as thread synchronization, process communication, and shared memory between related processes.

Uploaded by

Ren Zx
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
78 views14 pages

Solutions 2

This document contains solutions to exercises on system programming in Linux using C++. It includes examples of multithreading using mutexes, shared memory using mmap, inter-process communication using pipes, and spawning child processes using fork. The exercises cover concepts such as thread synchronization, process communication, and shared memory between related processes.

Uploaded by

Ren Zx
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 14

Faculty of Architecture and Engineering,

System Programming in Linux


Asst. Prof. Dr. Tolga YIRTICI
2023-2024 Fall Semester

Exercise Solutions

1) #include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // Mutex for synchronization
void printOddNumbers(int start, int end) {
for (int i = start; i <= end; i += 2) {
std::lock_guard<std::mutex> lock(mtx); // Lock the mutex to ensure thread safety
std::cout << i << " ";
}
}
int main() {
int range1 = 1;
int range2 = 1000;

// Create two threads, each responsible for printing odd numbers in a specific range
std::thread t1(printOddNumbers, range1, range2 / 2);
std::thread t2(printOddNumbers, range2 / 2 + 1, range2);
// Wait for both threads to finish

t1.join();
t2.join();

std::cout << std::endl;


return 0;
}

2) #include <iostream>
#include <thread>
#include <mutex>
#include <vector>

std::mutex mtx; // Mutex for synchronization


std::vector<int> primes;

bool isPrime(int num) {


for (int i = 2; i <= num / 2; ++i) {
if (num % i == 0) {
return false;
}
}
return true;
}

void findPrimes(int start, int end) {


for (int i = start; i <= end; ++i) {
if (isPrime(i)) {
std::lock_guard<std::mutex> lock(mtx);
primes.push_back(i);
}
}
}

int main() {
int range1 = 1;
int range2 = 1000;

std::thread t1(findPrimes, range1, range2 / 2);


std::thread t2(findPrimes, range2 / 2 + 1, range2);

t1.join();
t2.join();

std::cout << "Prime numbers between 1 and 1000: ";


for (int prime : primes) {
std::cout << prime << " ";
}
std::cout << std::endl;

return 0;
}

3) #include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx; // Mutex for synchronization


long long result = 1;

void calculateFactorial(int n) {
std::lock_guard<std::mutex> lock(mtx);
for (int i = 2; i <= n; ++i) {
result *= i;
}
}

int main() {
int number;

std::cout << "Enter a number: ";


std::cin >> number;

std::thread t1(calculateFactorial, number);


t1.join();

std::cout << "Factorial of " << number << ": " << result << std::endl;

return 0;
}

4) #include <iostream>
#include <fstream>
#include <thread>
#include <mutex>
#include <map>
#include <sstream>
#include <vector>

std::mutex mtx; // Mutex for synchronization


std::map<std::string, int> wordCount;
void countWordsInFile(const std::string& filename, int start, int end) {
std::ifstream file(filename);
std::string word;

file.seekg(start); // Set the file pointer to the start position

while (file.tellg() <= end && file >> word) {


std::lock_guard<std::mutex> lock(mtx);
++wordCount[word];
}
}

int main() {
const std::string filename = "sample.txt"; // Replace with your file name

std::ifstream file(filename, std::ios::binary | std::ios::ate);


std::streampos fileSize = file.tellg();

const int numThreads = 4; // Adjust the number of threads as needed


const std::streampos chunkSize = fileSize / numThreads;

std::vector<std::thread> threads;

for (int i = 0; i < numThreads; ++i) {


std::streampos start = i * chunkSize;
std::streampos end = (i == numThreads - 1) ? fileSize : (i + 1) * chunkSize - 1;
threads.emplace_back(countWordsInFile, filename, start, end);
}

for (std::thread& t : threads) {


t.join();
}

std::cout << "Word count in the file:" << std::endl;


for (const auto& pair : wordCount) {
std::cout << pair.first << ": " << pair.second << " times" << std::endl;
}

return 0;
}
5) #include <iostream>
#include <thread>
#include <mutex>
#include <vector>

const int NUM_PHILOSOPHERS = 5;


std::vector<std::mutex> forks(NUM_PHILOSOPHERS);
std::vector<std::thread> philosophers;

void philosopher(int id) {


int leftFork = id;
int rightFork = (id + 1) % NUM_PHILOSOPHERS;

// Simulating philosopher thinking


std::cout << "Philosopher " << id << " is thinking." << std::endl;

// Acquire left fork


forks[leftFork].lock();
std::cout << "Philosopher " << id << " picked up left fork." << std::endl;

// Acquire right fork


forks[rightFork].lock();
std::cout << "Philosopher " << id << " picked up right fork." << std::endl;

// Simulating philosopher eating


std::cout << "Philosopher " << id << " is eating." << std::endl;

// Release forks
forks[leftFork].unlock();
std::cout << "Philosopher " << id << " put down left fork." << std::endl;
forks[rightFork].unlock();
std::cout << "Philosopher " << id << " put down right fork." << std::endl;
}

int main() {
for (int i = 0; i < NUM_PHILOSOPHERS; ++i) {
philosophers.emplace_back(philosopher, i);
}
for (std::thread& t : philosophers) {
t.join();
}

return 0;
}

6) #include <iostream>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <functional>

class ThreadPool {
public:
explicit ThreadPool(size_t numThreads) : stop(false) {
for (size_t i = 0; i < numThreads; ++i) {
workers.emplace_back([this] {
while (true) {
std::function<void()> task;

{
std::unique_lock<std::mutex> lock(this->queueMutex);
this->condition.wait(lock, [this] {
return this->stop || !this->tasks.empty();
});

if (this->stop && this->tasks.empty()) {


return;
}

task = std::move(this->tasks.front());
this->tasks.pop();
}

task();
}
});
}
}

template<class F, class... Args>


auto enqueue(F&& f, Args&&... args) -> std::future<typename
std::result_of<F(Args...)>::type> {
using return_type = typename std::result_of<F(Args...)>::type;

auto task = std::make_shared<std::packaged_task<return_type()>>(


std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);

std::future<return_type> res = task->get_future();


{
std::unique_lock<std::mutex> lock(queueMutex);

if (stop) {
throw std::runtime_error("enqueue on stopped ThreadPool");
}

tasks.emplace([task]() { (*task)(); });


}
condition.notify_one();
return res;
}

~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queueMutex);
stop = true;
}
condition.notify_all();
for (std::thread& worker : workers) {
worker.join();
}
}

private:
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;

std::mutex queueMutex;
std::condition_variable condition;
bool stop;
};

int main() {
ThreadPool pool(4); // Adjust the number of threads as needed

// Example usage:
for (int i = 0; i < 8; ++i) {
pool.enqueue([i] {
std::cout << "Task " << i << " executed by thread " << std::this_thread::get_id() <<
std::endl;
});
}

return 0;
}

7) #include <iostream>
#include <vector>
#include <thread>
#include <algorithm>
#include <iterator>

template<typename RandomIt>
void parallel_sort(RandomIt begin, RandomIt end) {
if (begin == end)
return;

const size_t size = std::distance(begin, end);


const size_t threshold = 1000; // Adjust the threshold as needed

if (size <= threshold) {


std::sort(begin, end);
} else {
RandomIt middle = begin + size / 2;

std::future<void> first_half = std::async(parallel_sort<RandomIt>, begin, middle);


parallel_sort(middle, end);
first_half.wait();
std::inplace_merge(begin, middle, end);
}
}

int main() {
std::vector<int> vec = {5, 3, 1, 4, 2};
parallel_sort(vec.begin(), vec.end());

std::cout << "Sorted array: ";


for (int num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;

return 0;
}

8) #include <iostream>
#include <unistd.h>

int main() {
int pipe_fd[2];
pipe(pipe_fd);

pid_t pid1 = fork();

if (pid1 == 0) {
// Child Process 1
close(pipe_fd[1]); // Close write-end

int num;
while (read(pipe_fd[0], &num, sizeof(int)) > 0) {
num *= num;
write(pipe_fd[1], &num, sizeof(int));
}

close(pipe_fd[0]); // Close read-end


} else {
pid_t pid2 = fork();
if (pid2 == 0) {
// Child Process 2
close(pipe_fd[0]); // Close read-end

int squaredNum;
while (read(pipe_fd[1], &squaredNum, sizeof(int)) > 0) {
std::cout << "Squared Number: " << squaredNum << std::endl;
}

close(pipe_fd[1]); // Close write-end


} else {
// Parent Process
close(pipe_fd[0]); // Close unused read-end
close(pipe_fd[1]); // Close unused write-end

// Generate sequence of numbers


for (int i = 1; i <= 5; ++i) {
write(pipe_fd[1], &i, sizeof(int));
}

close(pipe_fd[1]); // Close write-end to signal the end


waitpid(pid1, nullptr, 0);
waitpid(pid2, nullptr, 0);
}
}

return 0;
}

9) #include <iostream>
#include <unistd.h>
#include <sys/wait.h>

int main() {
pid_t pid = fork();

if (pid == 0) {
// Child Process
execl("/bin/ls", "ls", nullptr); // Execute the 'ls' command
} else {
// Parent Process
wait(nullptr); // Wait for the child process to finish
}

return 0;
}

10) #include <iostream>


#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>

int main() {
const size_t SHARED_MEMORY_SIZE = sizeof(int);
int* sharedCounter = static_cast<int*>(mmap(nullptr, SHARED_MEMORY_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));

*sharedCounter = 0;

pid_t pid = fork();

if (pid == 0) {
// Child Process
for (int i = 0; i < 1000000; ++i) {
(*sharedCounter)++;
}
} else {
// Parent Process
wait(nullptr); // Wait for the child process to finish

std::cout << "Shared Counter: " << *sharedCounter << std::endl;

munmap(sharedCounter, SHARED_MEMORY_SIZE);
}

return 0;
}

11) #include <iostream>


#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

struct Message {
long mtype;
int data;
};

int main() {
key_t key = ftok("/tmp", 'X');
int msgid = msgget(key, IPC_CREAT | 0666);

pid_t producer_pid = fork();

if (producer_pid == 0) {
// Producer Process
for (int i = 1; i <= 5; ++i) {
Message msg;
msg.mtype = 1;
msg.data = i;

msgsnd(msgid, &msg, sizeof(msg.data), 0);


}
} else {
pid_t consumer_pid = fork();

if (consumer_pid == 0) {
// Consumer Process
for (int i = 1; i <= 5; ++i) {
Message msg;
msgrcv(msgid, &msg, sizeof(msg.data), 1, 0);
std::cout << "Received: " << msg.data * msg.data << std::endl;
}
} else {
// Parent Process
waitpid(producer_pid, nullptr, 0);
waitpid(consumer_pid, nullptr, 0);
msgctl(msgid, IPC_RMID, nullptr); // Remove message queue
}
}

return 0;
}

12) #include <iostream>


#include <fstream>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <unistd.h>
#include <sys/wait.h>

void countWordOccurrences(const std::string& filename) {


std::ifstream file(filename);
std::string word;
std::map<std::string, int> wordCount;

while (file >> word) {


std::transform(word.begin(), word.end(), word.begin(), ::tolower);
++wordCount[word];
}

for (const auto& pair : wordCount) {


std::cout << pair.first << ": " << pair.second << " times" << std::endl;
}
}

int main() {
pid_t pid = fork();

if (pid == 0) {
// Child Process
countWordOccurrences("sample.txt"); // Replace with your file name
} else {
// Parent Process
wait(nullptr); // Wait for the child process to finish
}
return 0;
}

You might also like