What is the difference between locking at same time vs one by one in dining philospher
that is lock(lck1, lck2)
vs lck1.lock() lck2.lock()
? I have tried both of them they are working fine. I have read about lock(lck1, lck2)
this way we can prevent deadlocks. As if one is acquired other not then it will release the acquired one and try again to acquire deadlocks. But what would be the impact of lock(lck1, lck2)
this here will it have something to related to performance. Please help i am new to multithreading.
#include <iostream>
#include <thread>
#include <functional>
#include <chrono>
#include <vector>
#include <mutex>
using namespace std;
class DiningPhilosophers {
private:
mutex mtx[5];
public:
DiningPhilosophers() { }
void wantsToEat(int philosopher, function<void()> pickLeftFork, function<void()> pickRightFork, function<void()> eat, function<void()> putLeftFork, function<void()> putRightFork) {
int left = philosopher;
int right = (philosopher + 1) % 5;
unique_lock<mutex> lck1(mtx[left], defer_lock); // defer_lock: init lck1 without locking mtx
unique_lock<mutex> lck2(mtx[right], defer_lock);
if (philosopher % 2 == 0) {
// lck1.lock(); // do NOT use std::lock(lck1, lck2)
// lck2.lock();
lock(lck1, lck2);
pickLeftFork(); pickRightFork();
} else {
lck2.lock();
lck1.lock();
pickLeftFork(); pickRightFork();
}
eat(); putRightFork(); putLeftFork();
// lck1 & lck2 are auto released after this line
}
};
void testPhilosopher(int philosopherId, DiningPhilosophers& diningPhilosophers) {
// Lambda functions to simulate the actions of a philosopher
auto pickLeftFork = [=]() { cout << "Philosopher " << philosopherId << " picked left fork." << endl; };
auto pickRightFork = [=]() { cout << "Philosopher " << philosopherId << " picked right fork." << endl; };
auto eat = [=]() {
cout << "Philosopher " << philosopherId << " is eating." << endl;
// Simulate eating time
this_thread::sleep_for(chrono::milliseconds(500));
};
auto putLeftFork = [=]() { cout << "Philosopher " << philosopherId << " put down left fork." << endl; };
auto putRightFork = [=]() { cout << "Philosopher " << philosopherId << " put down right fork." << endl; };
// Call the wantsToEat function for the philosopher
diningPhilosophers.wantsToEat(philosopherId, pickLeftFork, pickRightFork, eat, putLeftFork, putRightFork);
}
int main() {
DiningPhilosophers diningPhilosophers;
// Create five threads, each representing a philosopher
vector<thread> philosopherThreads;
for (int i = 0; i < 5; ++i) {
philosopherThreads.emplace_back(testPhilosopher, i, ref(diningPhilosophers));
}
// Wait for all threads to finish
for (auto& thread : philosopherThreads) {
thread.join();
}
return 0;
}