-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathproblem2.cpp
More file actions
133 lines (107 loc) · 3.07 KB
/
problem2.cpp
File metadata and controls
133 lines (107 loc) · 3.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// David Huynh
// COP 4520 - Spring 2024
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <shared_mutex>
#include <random>
#include <queue>
#define GUESTS 8
// I decided to implement a strategy using a queue and an availability status.
// Main class to simulate the showroom.
class ThreadQueue
{
private:
std::shared_mutex mtx;
std::queue<int> q;
// Variables for generating a random number.
std::random_device rd;
std::mt19937 mt;
std::uniform_int_distribution<int> dist;
public:
ThreadQueue() : mt(rd()), dist(0, 1)
{
}
// When a guest enters the showroom, they leave the queue and the showroom becomes "busy".
// When the function ends, the guest leaves and the showroom becomes "available".
void enterShowroom(int guestNumber)
{
std::unique_lock lock(mtx);
std::cout << "Guest " << guestNumber << " entered the showroom.\n";
// Leave the queue.
if (!q.empty())
{
q.pop();
}
}
// One thread at a time can enqueue.
void enqueue(int guestNumber)
{
std::unique_lock lock(mtx);
q.push(guestNumber);
// Uncomment the line below to view enqueue operations:
// std::cout << "(ENQUEUE) " << guestNumber << "\n";
}
// Multiple threads can check if they're at the front.
bool atFront(int guestNumber)
{
std::shared_lock lock(mtx);
if(!q.empty() && guestNumber == q.front())
{
return true;
}
return false;
}
// Allows a thread to decide if it wants to requeue.
bool requeue(int guestNumber)
{
std::unique_lock lock(mtx);
int check = dist(mt);
if (check == 0)
{
return false;
}
q.push(guestNumber);
// Uncomment the line below to view requeue operations:
// std::cout << "(REQUEUE) " << guestNumber << "\n";
return true;
}
};
// Thread function that places each thread in a queue.
void waitingRoom(ThreadQueue &tq, int myGuestNumber)
{
// Each guest enqueues once to guarantee a visit to the room.
tq.enqueue(myGuestNumber);
while (true)
{
// Each guest continuously checks if they're at the front of the queue.
if (tq.atFront(myGuestNumber) == true)
{
// If they're at the front, they can enter the showroom if it's available.
// If it's busy, the current thread waits until it isn't.
tq.enterShowroom(myGuestNumber);
// After entering, the guest can decide if they want to enqueue again.
if (tq.requeue(myGuestNumber) == false)
{
return;
}
}
}
}
// Main function which spawns GUESTS amount of threads.
int main(void)
{
std::vector<std::thread> pool(GUESTS);
ThreadQueue tq;
// Spawn the guests.
for (int i = 0; i < GUESTS; i++)
{
pool[i] = std::thread(waitingRoom, std::ref(tq), i+1);
}
for (auto &t : pool)
{
t.join();
}
return 0;
}