Code cleanup and stylization
This commit is contained in:
parent
e06a3dcd82
commit
1d7b6db0a3
@ -1,10 +1,12 @@
|
||||
|
||||
#ifndef PROJECT2_GRAPH_HPP_INCLUDED
|
||||
#define PROJECT2_GRAPH_HPP_INCLUDED
|
||||
#ifndef PROJECT2_INC_GRAPH_HPP
|
||||
#define PROJECT2_INC_GRAPH_HPP
|
||||
|
||||
#include <string> // string
|
||||
#include <vector> // vector<int>, vector<vector<int>
|
||||
|
||||
typedef std::vector<std::vector<int>> matrix;
|
||||
|
||||
class graph {
|
||||
public:
|
||||
// Constructors
|
||||
@ -12,6 +14,13 @@ public:
|
||||
// Initializers:
|
||||
// Read a graph from a file
|
||||
int read (std::string filename);
|
||||
// Error codes given off by read ()
|
||||
enum ERROR { INVALID_PROCESSES = 0b000001,
|
||||
INVALID_RESOURCES = 0b000010,
|
||||
INVALID_COUNTS = 0b000100,
|
||||
INVALID_ROWS = 0b001000,
|
||||
INVALID_COLUMNS = 0b010000,
|
||||
INVALID_FILENAME = 0b100000 };
|
||||
|
||||
// check functions:
|
||||
// is the graph...
|
||||
@ -22,8 +31,6 @@ public:
|
||||
// print the graph
|
||||
void print ();
|
||||
|
||||
typedef std::vector<std::vector<int>> matrix;
|
||||
|
||||
private:
|
||||
int num_processes = 0;
|
||||
int num_resources = 0;
|
||||
@ -31,4 +38,4 @@ private:
|
||||
matrix m; // Tell me, Mr. Anderson, what good is a phone call if you are unable to speak?
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // PROJECT2_INC_GRAPH_HPP
|
28
inc/read.hpp
Normal file
28
inc/read.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef PROJECT2_INC_READ_HPP
|
||||
#define PROJECT2_INC_READ_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/* stovi:
|
||||
* convert string s to vector<int> no matter the cost
|
||||
|
||||
@param &s const reference to a string
|
||||
|
||||
@returns vector<int>: signed integer representations
|
||||
of the groups of contiguous digits in the string
|
||||
*/
|
||||
std::vector<int> stovi (const std::string &s);
|
||||
|
||||
/* print_errpr_message:
|
||||
* Print the error message associated with the given error number
|
||||
|
||||
@param error int representing the error states of graph::read()
|
||||
@param filename string containing the name of a file
|
||||
|
||||
@returns void
|
||||
|
||||
*/
|
||||
void print_error_message (int error, std::string filename);
|
||||
|
||||
#endif // PROJECT2_INC_READ_HPP
|
@ -4,7 +4,7 @@
|
||||
| Created 2022-04-17 |
|
||||
+-----------------------------------------------+ */
|
||||
#include "graph.hpp"
|
||||
|
||||
// clang-format off
|
||||
void graph::print () {
|
||||
printf("num_processes: %d\nnum_resources: %d\n", num_processes, num_resources);
|
||||
printf("resource_counts: ["); for (auto e: resource_counts) printf("%d, ", e); printf("\b\b]\n");
|
||||
|
@ -14,7 +14,7 @@ int main(int argc, char** argv) {
|
||||
std::string filename = argv[1];
|
||||
graph g;
|
||||
|
||||
//TODO: Implement reading from a file
|
||||
// Read from a file, and print the result
|
||||
int err = g.read (filename);
|
||||
if (err) {
|
||||
return err;
|
||||
|
127
src/read.cpp
Normal file
127
src/read.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
/* +-------------+---------+-----------------------+
|
||||
| John Breaux | jab0910 | JohnBreaux@my.unt.edu |
|
||||
+-------------+---------+-----------------------+
|
||||
| Created 2022-04-17 |
|
||||
+-----------------------------------------------+ */
|
||||
#include "read.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
|
||||
#include "graph.hpp"
|
||||
|
||||
//* Vector of regex rules, in order of highest to lowest precedence
|
||||
std::vector<std::regex> patterns = {
|
||||
//* Rule 1: A line containing % is a comment, and should not be parsed
|
||||
std::regex ("(%)"),
|
||||
//* Rule 2: A line containing `num_processes` contains the number of processes
|
||||
std::regex ("(num_processes)\\D*(\\d+)"),
|
||||
//* Rule 3: A line containing `num_resources` contains the number of resources
|
||||
std::regex ("(num_resources)\\D*(\\d+)"),
|
||||
//* Rule 4: A line containing integers should be saved somewhere
|
||||
std::regex ("(-?[0-9]+.*-?[0-9]+)") // Magical!
|
||||
};
|
||||
|
||||
/* read:
|
||||
* Read from a file of name `filename`
|
||||
params:
|
||||
@param filename Name of the file to read graph from
|
||||
returns:
|
||||
@returns int: error code representing the list of errors in the lowest 6 bits
|
||||
*/
|
||||
int graph::read (std::string filename) {
|
||||
// Open file with name filename as input fstream
|
||||
std::ifstream f (filename);
|
||||
if (!f) {
|
||||
print_error_message (INVALID_FILENAME, filename);
|
||||
return INVALID_FILENAME;
|
||||
} // File bad!
|
||||
// Read the entire file
|
||||
while (f && !f.eof ()) {
|
||||
// acquire a line
|
||||
std::string line;
|
||||
std::getline (f, line);
|
||||
// Iterate over each pattern, and grab the associated data
|
||||
for (const auto &pattern: patterns) {
|
||||
std::smatch res;
|
||||
// Capture data with a regex search, using the pattern
|
||||
if (std::regex_search (line, res, pattern)) {
|
||||
// get the pattern type, value
|
||||
std::string type = res.format ("$1"), value = res.format ("$2");
|
||||
// Handle the pattern
|
||||
//* Rule 1: If line is a comment, ignore it and move on
|
||||
if (type == "%") break;
|
||||
|
||||
//* Rule 2: If num_processes= matched, assign value to num_processes
|
||||
else if (type == "num_processes") num_processes = std::stoi (value);
|
||||
|
||||
//* Rule 3: If num_resources= matched, assign value to num_resources
|
||||
else if (type == "num_resources") num_resources = std::stoi (value);
|
||||
|
||||
//* Rule 4: If this line is a comma-separated list of numbers:
|
||||
//* If resource_counts is empty, this is the resource counts,
|
||||
//* else it's part of the Matrix Reloaded
|
||||
else {
|
||||
if (resource_counts.size ()) m.push_back (stovi (type));
|
||||
else resource_counts = stovi (type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//* Test validity of the input file
|
||||
// Check if all sections are properly defined:
|
||||
int ret = 0;
|
||||
if (!num_processes)
|
||||
ret |= INVALID_PROCESSES;
|
||||
if (!num_resources)
|
||||
ret |= INVALID_RESOURCES;
|
||||
if (resource_counts.size () != num_resources)
|
||||
ret |= INVALID_COUNTS;
|
||||
if (m.size () != num_processes + num_resources)
|
||||
ret |= INVALID_ROWS;
|
||||
for (auto i: m) {
|
||||
if (i.size () != num_processes + num_resources) ret |= INVALID_COLUMNS;
|
||||
}
|
||||
// Print the appropriate error message
|
||||
if (ret) print_error_message (ret, filename);
|
||||
|
||||
// fstream destructor closes file when going out of scope
|
||||
// in this house we RAII sometimes.
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<int> stovi (const std::string &s) {
|
||||
// Create the number classification rule
|
||||
std::regex rule ("-?[0-9]+");
|
||||
// Make a new tokenizing iterator using the rule
|
||||
std::sregex_token_iterator start {s.begin (), s.end (), rule, 0}, end;
|
||||
// Match the numbers
|
||||
std::vector<int> res;
|
||||
for (auto i = start; i != end; ++i) res.push_back (atoi (i->str ().c_str ()));
|
||||
// give the numbers back
|
||||
return res;
|
||||
}
|
||||
|
||||
void print_error_message (int error, std::string filename) {
|
||||
// Error message strings
|
||||
const char err_please[] = "Check to ensure your input file is correct and follows the Rules.\n";
|
||||
const char err_undefn[] = "%s: Definition failed for %s\n";
|
||||
const char err_nofile[] = "%s: File not found.\n";
|
||||
const char *fn = filename.c_str ();
|
||||
// Test for each kind of error message, and print the appropriate messages
|
||||
if (error & graph::INVALID_PROCESSES)
|
||||
fprintf (stderr, err_undefn, fn, "num_processes");
|
||||
if (error & graph::INVALID_RESOURCES)
|
||||
fprintf (stderr, err_undefn, fn, "num_resources");
|
||||
if (error & graph::INVALID_COUNTS)
|
||||
fprintf (stderr, err_undefn, fn, "resource counts");
|
||||
if (error & graph::INVALID_ROWS)
|
||||
fprintf (stderr, err_undefn, fn, "adjacency matrix rows");
|
||||
if (error & graph::INVALID_COLUMNS)
|
||||
fprintf (stderr, err_undefn, fn, "adjacency matrix columns");
|
||||
if (error & graph::INVALID_FILENAME)
|
||||
fprintf (stderr, err_nofile, fn); // file not found
|
||||
if (error) printf (err_please);
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
/* +-------------+---------+-----------------------+
|
||||
| John Breaux | jab0910 | JohnBreaux@my.unt.edu |
|
||||
+-------------+---------+-----------------------+
|
||||
| Created 2022-04-17 |
|
||||
+-----------------------------------------------+ */
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include "graph.hpp"
|
||||
|
||||
//* Vector of regex rules, in order of precedence. Earlier entries will be checked before later entries.
|
||||
std::vector<std::regex> patterns = {
|
||||
//* Rule 1: A line containing % is a comment, and should not be parsed
|
||||
std::regex("(%)"),
|
||||
//* Rule 2: A line containing `num_processes` contains the number of processes
|
||||
std::regex("(num_processes)\\D*(\\d+)"),
|
||||
//* Rule 3: A line containing `num_resources` contains the number of resources
|
||||
std::regex("(num_resources)\\D*(\\d+)"),
|
||||
//* Rule 4: A line containing integers should be saved somewhere
|
||||
std::regex("(-?[0-9]+.*-?[0-9]+)") // Magical!
|
||||
};
|
||||
|
||||
// Say hi to Stovey, here to bake your cakes.
|
||||
//* convert string s to vector<int> no matter the cost
|
||||
std::vector<int> stovi (const std::string &s) {
|
||||
// Create the number classification rule
|
||||
std::regex rule("-?[0-9]+");
|
||||
// Make a new tokenizing iterator using the rule
|
||||
std::sregex_token_iterator start{s.begin(), s.end(), rule, 0}, end;
|
||||
// Match the numbers
|
||||
std::vector<int> res;
|
||||
for (auto i = start; i != end; ++i) res.push_back(atoi(i->str().c_str()));
|
||||
// give the numbers back
|
||||
return res;
|
||||
}
|
||||
|
||||
//* Read from a file of name `filename`
|
||||
int graph::read(std::string filename) {
|
||||
// Open file with name filename as input fstream
|
||||
std::ifstream f(filename);
|
||||
// Read the entire file
|
||||
while (!f.eof()) {
|
||||
// acquire a line
|
||||
std::string line;
|
||||
std::getline (f, line);
|
||||
// Iterate over each pattern, and grab the associated data
|
||||
for (const auto &pattern: patterns) {
|
||||
std::smatch res;
|
||||
// Capture data with a regex search, using the pattern
|
||||
if (std::regex_search (line, res, pattern)) {
|
||||
// get the pattern type, value
|
||||
std::string type = res.format("$1"), value = res.format("$2");
|
||||
// Handle the pattern
|
||||
// Rule 1: If line is a comment, ignore it and move on
|
||||
if (type == "%") break;
|
||||
|
||||
// Rule 2: If num_processes= matched, assign value to num_processes
|
||||
if (type == "num_processes") { num_processes = std::stoi(value); } else
|
||||
|
||||
// Rule 3: If num_resources= matched, assign value to num_resources
|
||||
if (type == "num_resources") { num_resources = std::stoi(value); } else
|
||||
|
||||
// Rule 4: If this line is a comma-separated list of numbers:
|
||||
// If resource_counts is empty, assume this is the resource counts,
|
||||
// else it's part of the matrix being reloaded
|
||||
if (!resource_counts.size()) { resource_counts = stovi(type); } else
|
||||
{ m.push_back(stovi(type)); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//* Test validity of the input file
|
||||
// Check if all sections are properly defined:
|
||||
const char errmsg[] = "%s: Definition failed for %s\n";
|
||||
int ret = 0;
|
||||
if (!num_processes){
|
||||
printf(errmsg, filename.c_str(), "num_processes");
|
||||
ret |= 0b00001;
|
||||
}
|
||||
if (!num_resources){
|
||||
printf(errmsg, filename.c_str(), "num_resources");
|
||||
ret |= 0b00010;
|
||||
}
|
||||
if (resource_counts.size() != num_resources){
|
||||
printf(errmsg, filename.c_str(), "resource counts");
|
||||
ret |= 0b00100;
|
||||
}
|
||||
if (m.size() != num_processes + num_resources){
|
||||
printf(errmsg, filename.c_str(), "adjacency matrix rows");
|
||||
ret |= 0b01000;
|
||||
}
|
||||
for (auto i: m) {
|
||||
if (i.size() != num_processes + num_resources)
|
||||
ret |= 0b10000;
|
||||
}
|
||||
if (ret & 0b10000) {
|
||||
printf(errmsg, filename.c_str(), "adjacency matrix columns");
|
||||
}
|
||||
if (ret) {
|
||||
printf("Check to ensure your input file is correct and follows the Rules.\n");
|
||||
}
|
||||
|
||||
// fstream destructor closes file when going out of scope
|
||||
// in this house we RAII sometimes.
|
||||
return ret;
|
||||
}
|
@ -7,21 +7,19 @@
|
||||
|
||||
using std::vector;
|
||||
|
||||
bool blocked(const int num_processes, const int num_resources, const vector<int> resource_counts, const graph::matrix &matrix, int process_id);
|
||||
bool blocked (const int num_processes, const int num_resources, const vector<int> resource_counts, const matrix &matrix, int process_id);
|
||||
|
||||
/* reducible:
|
||||
Perform the graph reduction algorithm on the adjacency matrix to detect deadlocks
|
||||
* Perform the graph reduction algorithm on the adjacency matrix to detect deadlocks
|
||||
This algorithm is described in section 5.2 of the Zybook
|
||||
|
||||
The graph reduction algorithm is implemented here with a few obvious optimizations:
|
||||
The algorithm should clear at least one blocked process per iteration;
|
||||
This leads to an easy failure condition, since fewer processes should be blocked than there are remaining iterations.
|
||||
By extension,
|
||||
@params: none, uses class-internal data
|
||||
@returns:
|
||||
bool:
|
||||
true if graph is deadlocked (not reducible)
|
||||
false if graph is not deadlocked (reducible)
|
||||
params:
|
||||
none
|
||||
returns:
|
||||
@returns bool: true if graph is deadlocked (not reducible), else false
|
||||
*/
|
||||
bool graph::reducible () {
|
||||
// Make a copy of the matrix, so we don't overwrite it
|
||||
@ -39,7 +37,8 @@ bool graph::reducible() {
|
||||
// erase unblocked process from the graph
|
||||
m_copy[p][p] = 0;
|
||||
for (int r = num_processes; r < num_processes + num_resources; r++) {
|
||||
m_copy[r][p] = 0; m_copy[p][r] = 0;
|
||||
m_copy[r][p] = 0;
|
||||
m_copy[p][r] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -48,14 +47,28 @@ bool graph::reducible() {
|
||||
// If more processes are blocked than can be cleared before the algorithm finishes, give up
|
||||
if (num_blocked == num_processes - num_iterations) return true;
|
||||
// Print the new matrix
|
||||
// clang-format off
|
||||
printf("| ");for(auto x:m_copy){for(auto y:x)printf("%d, ",y);printf("\b\b |\n| ");}printf("\b\b \b\b");
|
||||
// clang-format on
|
||||
// If no processes are blocked, we won!
|
||||
if (num_blocked == 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool blocked(const int np, const int nr, const vector<int> rc, const graph::matrix &m, int process_id) {
|
||||
/* blocked:
|
||||
Checks if a process is blocked for a given state of the graph
|
||||
params:
|
||||
@param np num_processes
|
||||
@param nr num_resources
|
||||
@param rc resource_counts
|
||||
@param m adjacency matrix
|
||||
@param id process ID (0-indexed, ascending)
|
||||
returns:
|
||||
@returns bool: true when blocked, else false
|
||||
|
||||
*/
|
||||
bool blocked (const int np, const int nr, const vector<int> rc, const matrix &m, int id) {
|
||||
//* Calculate free resources, and compare free units to requests
|
||||
vector<int> resources = rc;
|
||||
for (int r = 0; r < nr; r++) {
|
||||
@ -66,7 +79,7 @@ bool blocked(const int np, const int nr, const vector<int> rc, const graph::matr
|
||||
resources[r] -= m[r + np][p];
|
||||
}
|
||||
// If the program requests more resources than are available, it's blocked
|
||||
if (m[process_id][r+np] > resources[r]) {
|
||||
if (m[id][r + np] > resources[r]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user