0% found this document useful (0 votes)
106 views33 pages

Operating Systems: Project Reports

This document contains a summary of operating system projects for a software engineering student. It describes three projects, with Project 1 involving the validation of Sudoku puzzles using multithreaded programming. The source code provided implements Project 1 by creating 11 threads to check columns, rows, and 3x3 subgrids for valid digits. The main function runs the threads, joins them, and checks their results to determine if the puzzle is solved.
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)
106 views33 pages

Operating Systems: Project Reports

This document contains a summary of operating system projects for a software engineering student. It describes three projects, with Project 1 involving the validation of Sudoku puzzles using multithreaded programming. The source code provided implements Project 1 by creating 11 threads to check columns, rows, and 3x3 subgrids for valid digits. The main function runs the threads, joins them, and checks their results to determine if the puzzle is solved.
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/ 33

Operating Systems

Project Reports

Class : SE

Major : software engineering

Name : nigussie nafiyad reta Student ID:


201932130104

P1 P2 P3 P4 Total
College of Mathematics and Computer Science

Content
Project 1.................................................................................................................................................. 1
Project 2.................................................................................................................................................. 2

Project 1 — Sudoku Solution Validator.


A Sudoku puzzle uses a 9 × 9 grid in which each column and
row, as well as each of the nine 3 × 3 subgrids, must contain all
of the digits 1 ⋅⋅⋅ 9. Figure 4.26 presents an example of a valid
Sudoku puzzle. This project consists of designing a
multithreaded application that determines whether the
solution to a Sudoku puzzle is valid.
There are several different ways of multithreading this
application. One suggested strategy is to create threads that
check the following criteria:
• A thread to check that each column contains the digits 1
through 9.

• A thread to check that each row contains the digits 1


through 9.

• Nine threads to check that each of the 3 × 3 subgrids


contains the digits 1 through 9.
This would result in a total of eleven separate threads for
validating a Sudoku puzzle. However, you are welcome to
create even more threads for this project. For example, rather
than creating one thread that checks all nine columns, you
could create nine separate threads and have each of them
check one column.

Source code

#include <stdio.h>
#include <stdlib.h>
int board[9][9]; //The sudoku file is imported
into this board
/* You will need to declare an array of integer
values that is visible to each thread. The value
in the array (0 or 1) indicates whether the
worker thread's number is valid (see
"Returning Results to the Parent Thread" in the
textbook's project description) */
int valid[11]; //When the threads are joined, if
that thread is a valid part of a sudoku puzzle, it
returns 1 to valid[], else it returns 0
int subgridCt = 2; //used to track through valid
array sections for the 3x3 subgrids
/* You will need a structure to store the
information to be passed to each thread (see
"Passing Parameters to Each Thread" in the
textbook's project description)*/
typedef struct{

int row;
int column;

}parameters;
//declare the threads
pthread_t col_thread, row_thread,
first_thread, second_thread, third_thread,
fourth_thread, fifth_thread, sixth_thread,
seventh_thread, eighth_thread, ninth_thread;
/* Declare the thread that checks columns,
rows and 3x3 subgrids */
void *column_worker(void *param);
void *row_worker(void *param);
void *square_worker(void *param);
int main(int argc, char *argv[])
{
int j = 0; //used in for loop to read in file
elements to board array
int i = 0; //used in for loop to read in file
elements to board array
int k = 0; //used in while loop to check
valid array

//Error checking: if user only enters ./hw2


then gets this error
if (argc == 1) {
fprintf(stderr,"Usage: ./hw2 <sudoku
grid>\n");
return -1;
}

//reading file from agrv[] and portioning


the numbers to the sudoku board
FILE *sudoku;
sudoku = fopen(argv[1], "r");
for(i = 0; i < 9; i++){
for(j = 0; j < 9; j++){
fscanf(sudoku, "%d ", &board[i]
[j]);
}
}

/*You need to assign values to the


structure variable. Then you can create
multiple worker threads by passing the
information using the structure variable*/
parameters *checkRows = (parameters *)
malloc(sizeof(parameters));
checkRows->row = 0;
checkRows->column = 0;

parameters *checkCols = (parameters *)


malloc(sizeof(parameters));
checkCols->row = 0;
checkCols->column = 0;

parameters *first3by3 = (parameters *)


malloc(sizeof(parameters));
first3by3->row = 0;
first3by3->column = 0;

parameters *second3by3 = (parameters *)


malloc(sizeof(parameters));
second3by3->row = 0;
second3by3->column = 3;

parameters *third3by3 = (parameters *)


malloc(sizeof(parameters));
third3by3->row = 0;
third3by3->column = 6;

parameters *fourth3by3 = (parameters *)


malloc(sizeof(parameters));
fourth3by3->row = 3;
fourth3by3->column = 0;
parameters *fifth3by3 = (parameters *)
malloc(sizeof(parameters));
fifth3by3->row = 3;
fifth3by3->column = 3;

parameters *sixth3by3 = (parameters *)


malloc(sizeof(parameters));
sixth3by3->row = 3;
sixth3by3->column = 6;

parameters *seventh3by3 = (parameters


*) malloc(sizeof(parameters));
seventh3by3->row = 6;
seventh3by3->column = 0;

parameters *eighth3by3 = (parameters *)


malloc(sizeof(parameters));
eighth3by3->row = 6;
eighth3by3->column = 3;
parameters *ninth3by3 = (parameters *)
malloc(sizeof(parameters));
ninth3by3->row = 6;
ninth3by3->column = 6;

//return values? this is used for pthread


join
void * rows;
void * cols;
void * first_square;
void * second_square;
void * third_square;
void * fourth_square;
void * fifth_square;
void * sixth_square;
void * seventh_square;
void * eighth_square;
void * ninth_square;
//create the pthreads(pthread_t,
pthread_attr (NULL), pthread function, copy of
struct for pthread)
pthread_create(&col_thread, NULL,
column_worker, (void *) checkCols);
pthread_create(&row_thread, NULL,
row_worker, (void *) checkRows);
pthread_create(&first_thread, NULL,
square_worker, (void *) first3by3);
pthread_create(&second_thread, NULL,
square_worker, (void *) second3by3);
pthread_create(&third_thread, NULL,
square_worker, (void *) third3by3);
pthread_create(&fourth_thread, NULL,
square_worker, (void *) fourth3by3);
pthread_create(&fifth_thread, NULL,
square_worker, (void *) fifth3by3);
pthread_create(&sixth_thread, NULL,
square_worker, (void *) sixth3by3);
pthread_create(&seventh_thread, NULL,
square_worker, (void *) seventh3by3);
pthread_create(&eighth_thread, NULL,
square_worker, (void *) eighth3by3);
pthread_create(&ninth_thread, NULL,
square_worker, (void *) ninth3by3);

/*You need to call pthread_join() for each


children thread so that the parent will wait*/
pthread_join(col_thread, &cols);
pthread_join(row_thread, &rows);
pthread_join(first_thread, &first_square);
pthread_join(second_thread,
&second_square);
pthread_join(third_thread,
&third_square);
pthread_join(fourth_thread,
&fourth_square);
pthread_join(fifth_thread, &fifth_square);
pthread_join(sixth_thread,
&sixth_square);
pthread_join(seventh_thread,
&seventh_square);
pthread_join(eighth_thread,
&eighth_square);
pthread_join(ninth_thread,
&ninth_square);

/* Finally, after all children returns, you


can check the status array that is visible to
everyone and see if it is valid. You then print
out the final checking result*/
while(k < 11){

/*if the thread is valid (contains all


numbers 1-9) then the value of valid[k] will be
1, continue to check all elements of valid until
either the array ends (k = 11) or the
value of valid[k] is 0. If the loop terminates on
its own (k = 11), then print the "is Solved"
statement and
* exit the program. If the value is 0 then
there is a thread that did was not a valid part
of a sudoku puzzle and the whole puzzle is
invalid. Print
* the "NOT Solved" statement and end
the program.
*/
if(valid[k] == 1){
k++;
}
else{
printf("The Sudoku Puzzle is NOT
solved. \n");
exit(0);
}

}
printf("The Sudoku Puzzle is solved. \n");

return 0;
}
/*thread code for child checking all columns*/
void *column_worker(void *params)
{
int i, j;
parameters * c_worker = (parameters *)
params;
int beginCol = c_worker->column;
int beginRow = c_worker->row;
/*sorting sudoku column; this will put the
column into a sorted order and check for
duplicates
if there are duplicates, this section is not
valid and returns 0 for the column_worker;*/

for(i = beginCol; i < 9; i++){

int col[9]= {0}; //array to hold sorted


column

for(j = beginRow; j < 9; j++){

int val = board[i][j]; //this specific value


in the column

/*if the coresponding array element for


the value is 0, it has not been seen and
we will input this value to the sorted
column array. */

if(col[val-1] == 0 && val > 0){


col[val-1] = val;

}
/*if the value is not 0, then the value
is a duplicate and the sudoku puzzle
is not solved or valid so the value of
column_worker in valid is 0; */
else{
valid[0] = 0;
pthread_exit(0);
}
}
}
valid[0] = 1;
pthread_exit(0);
}
/*thread code for child checking all rows*/
void *row_worker(void *params){
int i, j;

parameters * r_worker = (parameters *)


params;
int beginCol = r_worker->column;
int beginRow = r_worker->row;

/*sorting sudoku row; this will put the row


into a sorted order and check for duplicates
if there are duplicates, this section is not
valid and returns 0 for the row_worker;*/

for(i = beginCol; i < 9; i++){

int row[9]= {0};//array to hold sorted row

for(j = beginRow; j < 9; j++){

int val = board[i][j];


/*if the corresponding array element for
the value is 0, it has not been seen and
we will input this value to the sorted
column array. */

if(row[val-1] == 0 && val > 0){


row[val-1] = val;
}

/*if the value is not 0, then the value is


a duplicate and the sudoku puzzle
is not solved or valid so the value of
column_worker in valid is 0. */

else{
valid[1] = 0;
pthread_exit(0);
}
}
}
valid[1] = 1;
pthread_exit(0);
}
/*thread code for child checking all 3x3
subgrids*/
void *square_worker(void *params){

int i, j;
parameters * worker = (parameters *)
params;
int beginRow = worker->row;
int beginCol = worker->column;

/*sorting sudoku subgrids; this will put the


3x3 subgrid, as determined by the beginRow
and beginCol parameters
into a sorted order and check for
duplicates. if there are duplicates, this section
is not valid and returns 0 for the
square_worker;*/

int square[9] = {0}; //1d array to hold sorted


3x3 square
for (i = beginRow; i < beginRow + 3; ++i) {
for (j = beginCol; j < beginCol + 3; ++j) {

int val = board[i][j];

/*if the corresponding array element for


the value is 0, it has not been seen and
we will input this value to the sorted
column array. */

if (square[val-1] == 0 && val > 0) {


square[val-1] = val;
}

/*if the value is not 0, then the value is


a duplicate and the sudoku puzzle
is not solved or valid so the value of
square_worker in valid is 0. */

else{
valid[subgridCt] = 0;
subgridCt++;
pthread_exit(0);
}
}
}
valid[subgridCt] = 1;
subgridCt++;
pthread_exit(0);
}

Project 2—Multithreaded Sorting Application


This programming project will require passing parameters to
each of the sorting threads. In particular, it will be necessary to
identify the starting index from which each thread is to begin
sorting. Refer to the instructions in Project 1 for details on
passing parameters to a thread. The parent thread will output
the sorted array once all sorting threads have exited.ls
To compile: $ make
To run: $ make run NUM = #
To Clean: $ make clean

Source code

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define M 8
#define N 1024

// arrays shared among threads


int unsorted[N];
int sorted[N];

// THOUGHT: Make another type for sort_mate which doesn't


need tid?
typedef struct {
int m;
int n;
int start_index;
} parameters;

void *node(void *param);


void *leaf(void *param);

void seedArray(int *arr, int size, int min, int max);


void bubbleSort(int *arr, int size);
void mergeSortedLists(int *arr1, int *arr2, int *mergedArr, int
size);

// TODO: Pass in N and M values in argv (also check to make


sure pwr of 2 and N/M valid)
int main(int argc, char *argv[]) {

clock_t start;
float execution_time;
pthread_t main_thread_id;
pthread_attr_t thread_attr; // thread attributes

parameters *main_thread_params = (parameters *)


malloc(sizeof(parameters));
main_thread_params->m = M;
main_thread_params->n = N;
main_thread_params->start_index = 0;

// printf("Size of parameters ptr: %lu\n",


sizeof(main_thread_params));
// printf("Size of parameters: %lu\n",
sizeof(*main_thread_params));

seedArray(unsorted, N, 0, 50);

start = clock();
// get default attributes
pthread_attr_init(&thread_attr);

// create the main thread


pthread_create(&main_thread_id, &thread_attr, node,
main_thread_params);

// wait for the thread to exit


pthread_join(main_thread_id, NULL);

execution_time = ((float)(clock() - start))/CLOCKS_PER_SEC;

printf("Number of threads: %d\nLength of list: %d\n",M,N);


printf("Execution Time (secs): %f\n", execution_time);

free(main_thread_params);
return 0;
}

// Merger Thread
void *node(void *param) {
//printf("Node Thread entered\n");

pthread_attr_t thread_attr; // thread attributes


pthread_attr_init(&thread_attr); // using default attr for all

int i = 0;

parameters *sp = param;


int m = sp->m;
int n = sp->n;
int start = sp->start_index;
/* STEPS:
1. Create threads until m==1
2. Sort remaining length to which we're assigned
3. Wait for threads to complete (in reverse order of
creation)
4. Merge each thread as it is ready
*/

// Step 1. Will need to create new params to pass in (multiple


structs so need params* array)

// Trying static allocation to confirm this thing even works


parameters *child_params[M-1];
// and space for tids
pthread_t child_thread_id[M-1];

while(m > 1) {
//printf("Making child params from: m = %d, n = %d,
start_index = %d\n", m, n, start);
child_params[i] = (parameters *) malloc(sizeof(parameters));
child_params[i]->m = m/2;
child_params[i]->n = n/2;
child_params[i]->start_index = n/2 + start; // (n/m)*(m/2) =
n/2
// create the thread
if (m > 2) {
//printf("Creating Node Thread: m = %d, n = %d, st_ind =
%d\n", child_params[i]->m, child_params[i]->n,
child_params[i]->start_index);
pthread_create(&child_thread_id[i], &thread_attr, node,
child_params[i]);
}
else { // last thread created should be leaf
//printf("Creating Leaf Thread: m = %d, n = %d, st_ind =
%d\n", child_params[i]->m, child_params[i]->n,
child_params[i]->start_index);
pthread_create(&child_thread_id[i], &thread_attr, leaf,
child_params[i]);
}

m/=2;
n/=2;
i++;
}
// int i will be equal to # of child threads created

//printf("Node thread done spawning threads, continuing to


sort: i = %d, m = %d, n = %d \n", i, m, n);
// Step 2. Do our sorting
bubbleSort(unsorted + start, n);

// Forgot to change up arrays while merging


i--; // or i = 0;
// Step 3 (and 4). Wait for threads to complete, merging as
they are (complete)
while (i >= 0) {
pthread_join(child_thread_id[i], NULL);
//printf("Node thread: a child finished, merging...\n");
mergeSortedLists(unsorted + start, unsorted + start + n,
sorted, n);
i--;
// m*=2; // m not used anymore so doesn't really matter
n*=2;
}

pthread_exit(0);
}

// Sorter Thread
void *leaf(void *param) {
//printf("Leaf Thread entered\n");

parameters *sp = param;

bubbleSort(unsorted + sp->start_index, sp->n);


//printf("Leaf Thread done sorting\n");

pthread_exit(NULL);
}

void seedArray(int *arr, int size, int min, int max) {


srand((unsigned)time(NULL));

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


arr[i] = rand()% (max - min + 1) + min;
}
}
void bubbleSort(int *arr, int size) {
int i;
int j;
int swap;

for (i = 0; i < size - 1; i++) {


for (j = 0; j < size - i - 1; j++) {
if (arr[j] > arr[j+1]) {
swap = arr[j];
arr[j] = arr[j+1];
arr[j+1] = swap;
}
}
}

}
// size here is size of each array
void mergeSortedLists(int *arr1, int *arr2, int *mergedArr, int
size) {

int i = 0;
int j = 0;
int k = 0;

// walk each array, copying smaller of two elements


while (j < size && k < size) {
if (arr1[j] <= arr2[k]) {
mergedArr[i++] = arr1[j++];
}
else {
mergedArr[i++] = arr2[k++];
}
}
// if there are remaining elements in one array (not sure
which), copy them over
while(j < size) {
mergedArr[i++] = arr1[j++];
}
while(k < size) {
mergedArr[i++] = arr2[k++];
}

// copy back to source array


for (i = 0; i < size*2; i++) {
arr1[i] = mergedArr[i];
}
}

You might also like