stuff
This commit is contained in:
@@ -77,7 +77,7 @@ int main(void)
|
||||
}
|
||||
```
|
||||
|
||||
You should have already picked an editor or IDE to use. Compiling at the command line is sometimes easier than using an IDE as IDEs sometimes hide error messages. Edit, compile, and run your program entirely from the Linux VM. Using Windows to edit the file and then transferring to Linux can cause formatting problems with the code and might introduce unexpected errors.
|
||||
You should have already picked an editor or IDE to use. Compiling at the command line is sometimes easier than using an IDE as IDEs sometimes hide error messages.
|
||||
|
||||
You can invoke the compiler at the command line directly:
|
||||
|
||||
@@ -204,50 +204,18 @@ Another, highly recommended, tool for you to use is valgrind. Valgrind will mon
|
||||
|
||||
## Deliverables
|
||||
|
||||
You should have at least three source files in your project:
|
||||
You will need to include all your source files and any other resources you used to complete lab.
|
||||
|
||||
1. smTester.c – The test driver for your stack machine and should contain the 'main' function. Make sure your implemented test driver tests more than just the sample
|
||||
2. stackm.c – the implementation file for your stack machine operations
|
||||
3. stackm.h – the header file that defines the stack machine operations
|
||||
A makefile is useful, but optional for this assignment. If you created a makefile, include it in your submission.
|
||||
|
||||
A makefile is useful, but optional for this assignment. If you created a makefile, include it in your submission.
|
||||
All files should be well documented with function comment blocks and inline comments that explain complicated code routines. While no explicit style guidelines are set for programming in this course, code should be documented and readable. Include your name, section, and lab name in a comment block at the top of each file.
|
||||
|
||||
All files should be well documented with function comment blocks and inline comments that explain complicated code routines. While no explicit style guidelines are set for programming in this course, code should be documented and readable. Include your name, section, and lab name in a comment block at the top of each file, including the given header file.
|
||||
|
||||
NOTE: do ***NOT*** submit any IDE configuration files (.idea, project files, etc.). Only submit your source files and report.
|
||||
|
||||
Prepare a lab report and submit it along with your source code. The report should include the following:
|
||||
|
||||
- Your name, date, and lab title
|
||||
- Introduction – a description of the lab in your own words
|
||||
- Design and Testing Methodology – a description of your design decisions and the process you took to create your test driver
|
||||
- Resources – a description of any external resources you used to complete the lab
|
||||
- Build – instructions on how to build and run your program. Include the exact commands that are necessary
|
||||
- Analysis – Discuss the key concepts from the lab and answers to the following questions
|
||||
- All the stack machine functions need a "reference" to the stack structure, and according to this design, that stack reference is passed as a pointer. Why is this necessary? Do all the stack functions need this to be passed as a pointer? Any exceptions? Be specific in your answer.
|
||||
- Unlike a Java or C++ implementation, this implementation cannot "hide" any of the internal structure of the stack. That is, users of the stack could mess up the next pointers if they are careless. Can you think of any way we could hide the structure of the stack to lessen the chances a user will mess up the stack? Describe in brief detail.
|
||||
- What if all smClear() did was assign NULL to top in the stack structure and nothing else. Would the program crash? Would there be any side effects? Try it and report results.
|
||||
- Give an example of why it might be helpful to provide an iterator or random access to elements stored in the stack (rather than always accessing the top) and outline how you could implement such a feature.
|
||||
- Conclusion
|
||||
- Summary of what you learned in the lab
|
||||
- What specifically was challenging about this lab?
|
||||
- What did you like about it?
|
||||
- What could we do to improve it for others?
|
||||
NOTE: do ***NOT*** submit any IDE configuration files (.idea, project files, etc.). Only submit your source files.
|
||||
|
||||
NOTE: You should ensure that this program compiles without warning (-Wall and -Wextra) prior to submitting.
|
||||
|
||||
Create a zip file containing your source files and your report and submit the zip file per your instructor's instructions.
|
||||
Prepare a zip file with all submitted files and upload the file to Canvas per your instructor's instructions.
|
||||
|
||||
## Grading Criteria (100 Points)
|
||||
|
||||
- (35 Points) Report
|
||||
- (5 Points) Report Introduction - Thorough description of the lab in your own words.
|
||||
- (5 Points) Design and Testing Methodology - Detailed description of design and method for testing your implementation.
|
||||
- (20 Points) Analysis - Answers to the analysis questions
|
||||
- (5 Points) Conclusion - Thorough conclusion with description of what you learned, what you liked, and suggestions for lab improvements.
|
||||
- (5 Points) Documented Resources - Description of external resources used to complete the lab
|
||||
- (5 Points) Correct Submission - Followed submission instructions (e.g. IDE project files are not submitted)
|
||||
- (5 Points) Build - Code compiles without warnings or errors
|
||||
- (10 Points) Test Cases - Thoroughness of submitted test driver
|
||||
- (35 Points) Instructor Tests - Implementation passes all instructor test cases
|
||||
- (5 Points) Memory Management - Program execution is free from memory leaks
|
||||
Demonstrate that your lab is working by compiling it, running it, and running any test code in person during lab hours.
|
||||
@@ -154,50 +154,18 @@ Make sure your shell supports all the features listed in the "Development Requir
|
||||
|
||||
## Deliverables
|
||||
|
||||
You will need to include all your source files and any other resources you used to complete lab. Please don't just google search for a solution, but if you do use Google for any help, include a description and URL of what you used to help you.
|
||||
You will need to include all your source files and any other resources you used to complete lab.
|
||||
|
||||
A makefile is useful, but optional for this assignment. If you created a makefile, include it in your submission.
|
||||
|
||||
All files should be well documented with function comment blocks and inline comments that explain complicated code routines. While no explicit style guidelines are set for programming in this course, code should be documented and readable. Include your name, section, and lab name in a comment block at the top of each file.
|
||||
|
||||
NOTE: do ***NOT*** submit any IDE configuration files (.idea, project files, etc.). Only submit your source files and report.
|
||||
|
||||
Prepare a lab report and submit it along with your source code. The report should include the following:
|
||||
|
||||
- Your name, section, date, and lab title
|
||||
- Introduction – a description the lab in your own words
|
||||
- Design – a description of your design decisions in creating your solution
|
||||
- Resources – a description of any external resources you used to complete the lab
|
||||
- Build – instructions on how to build and run your program. Include the exact commands that are necessary
|
||||
- Analysis – Discuss the key concepts from the lab and answers to the following questions
|
||||
- Commands in TTSH are executed by a call to ```fork()``` followed by a call to ```exec()```. What would bee the behavior of teeny tiny shell if the calls were reversed?
|
||||
- There are many 'flavors' of ```exec()```. For this lab you used ```execvp```, research the other 'flavors' of ```exec()```. What is each used for? Be sure to site your sources:
|
||||
- execl
|
||||
- execlp
|
||||
- execle
|
||||
- execv
|
||||
- execvp
|
||||
- execvpe
|
||||
- For this lab you used the ```fork()``` system call to create a child process to execute the command. There is another version of fork called ```vfork()```. Research this system call and describe how it works. Be sure to site your sources. When would you choose to use ```vfork()``` instead of ```fork()```.
|
||||
- Conclusion
|
||||
- Summary of what you learned in the lab
|
||||
- What specifically was challenging about this lab?
|
||||
- What did you like about it?
|
||||
- What could we do to improve it for others?
|
||||
NOTE: do ***NOT*** submit any IDE configuration files (.idea, project files, etc.). Only submit your source files.
|
||||
|
||||
NOTE: You should ensure that this program compiles without warning (-Wall and -Wextra) prior to submitting.
|
||||
|
||||
Prepare a zip file with all submitted files and upload the file to Canvas per your instructor's instructions.
|
||||
|
||||
## Grading Criteria
|
||||
## Grading Criteria (100 Points)
|
||||
|
||||
- (35 Points) Report
|
||||
- (5 Points) Report Introduction - Thorough description of the lab in your own words.
|
||||
- (5 Points) Design and Testing Methodology - Detailed description of design and method for testing your implementation.
|
||||
- (20 Points) Analysis - Answers to the analysis questions
|
||||
- (5 Points) Conclusion - Thorough conclusion with description of what you learned, what you liked, and suggestions for lab improvements.
|
||||
- (5 Points) Documented Resources - Description of external resources used to complete the lab
|
||||
- (5 Points) Correct Submission - Followed submission instructions (e.g. IDE project files are not submitted)
|
||||
- (5 Points) Build - Code compiles without warnings or errors
|
||||
- (45 Points) Instructor Tests - Implementation passes all instructor test cases
|
||||
- (5 Points) Memory Management - Program execution is free from memory leaks
|
||||
Demonstrate that your lab is working by compiling it, running it, and running any test code in person during lab hours.
|
||||
|
||||
@@ -215,46 +215,18 @@ There are [several matrix files](matrices.zip) located provided along with this
|
||||
|
||||
## Deliverables
|
||||
|
||||
You will need to include all your source files, test case matrix files, and any other resources you used to complete lab. Please don't just google search for a solution, but if you do use Google for any help, include a description and URL of what you used to help you.
|
||||
You will need to include all your source files and any other resources you used to complete lab.
|
||||
|
||||
A makefile is useful, but optional for this assignment. If you created a makefile, include it in your submission.
|
||||
A makefile is useful, but optional for this assignment. If you created a makefile, include it in your submission.
|
||||
|
||||
All files should be well documented with function comment blocks and inline comments that explain complicated code routines. While no explicit style guidelines are set for programming in this course, code should be documented and readable. Include your name, section, and lab name in a comment block at the top of each file.
|
||||
|
||||
NOTE: do ***NOT*** submit any IDE configuration files (.idea, project files, etc.). Only submit your source files and report.
|
||||
|
||||
Prepare a lab report and submit it along with your source code. The report should include the following:
|
||||
|
||||
- Your name, section, date, and lab title
|
||||
- Introduction – a description of the lab in your own words
|
||||
- Design – a description of your design decisions in creating your solution
|
||||
- Resources – a description of any external resources you used to complete the lab
|
||||
- Build – instructions on how to build and run your programs. Include the exact commands that are necessary
|
||||
- Analysis – Your two programs (single process and multiprocess) need to print out the time to perform the matrix addition. Use this information to evaluate the usefulness of multiprocess programming. Is there an advantage to using multiprocessing for matrix addition? Be thorough.
|
||||
<br/>In addition, answer the following in your analysis
|
||||
- How does the runtime of the single process compare to the multiple process version? Faster? Slower? Why do you think this is the case? Think in terms of operating system overhead.
|
||||
- How could identifying patterns in the source matrices be used to speed up the computation?
|
||||
- How does shared memory affect the overall heap needed by the process? If you run your program using valgrind, it will print out a summary of the total heap used. What conclusions can you draw from this?
|
||||
- Conclusion
|
||||
- Summary of what you learned in the lab
|
||||
- What specifically was challenging about this lab?
|
||||
- What did you like about it?
|
||||
- What could we do to improve it for others?
|
||||
NOTE: do ***NOT*** submit any IDE configuration files (.idea, project files, etc.). Only submit your source files.
|
||||
|
||||
NOTE: You should ensure that this program compiles without warning (-Wall and -Wextra) prior to submitting.
|
||||
|
||||
Prepare a zip file with all submitted files and upload the file to Canvas per your instructor's instructions.
|
||||
|
||||
## Grading Criteria
|
||||
## Grading Criteria (100 Points)
|
||||
|
||||
- (35 Points) Report
|
||||
- (5 Points) Report Introduction - Thorough description of the lab in your own words.
|
||||
- (5 Points) Design and Testing Methodology - Detailed description of design and method for testing your implementation.
|
||||
- (20 Points) Analysis - Answers to the analysis questions
|
||||
- (5 Points) Conclusion - Thorough conclusion with description of what you learned, what you liked, and suggestions for lab improvements.
|
||||
- (5 Points) Documented Resources - Description of external resources used to complete the lab
|
||||
- (5 Points) Correct Submission - Followed submission instructions (e.g. IDE project files are not submitted)
|
||||
- (5 Points) Build - Code compiles without warnings or errors
|
||||
- (10 Points) Test Cases - Thoroughness of submitted test cases
|
||||
- (35 Points) Instructor Tests - Implementation passes all instructor test cases
|
||||
- (5 Points) Memory Management - Program execution is free from memory leaks. All shared memory segments are cleaned up.
|
||||
Demonstrate that your lab is working by compiling it, running it, and running any test code in person during lab hours.
|
||||
230
04-MatrixAddition (pthread)/README.md
Normal file
230
04-MatrixAddition (pthread)/README.md
Normal file
@@ -0,0 +1,230 @@
|
||||
## Introduction
|
||||
|
||||
The purpose of this lab is to design, code, and test programs to add two matrices together using both a multi-threaded program. It is intended to familiarize yourself with the system calls needed to create threads on linux.
|
||||
|
||||
The matrices will be read from a file. The format for the file is given later.
|
||||
|
||||
## References
|
||||
|
||||
You will be using the ```fork()``` system call to create child processes to compute a portion of matrix addition. The children will then write their result to the correct position in a matrix stored in shared memory. You will also be timing your code's executing using the ```clock_gettime()``` system call. Before you start, it might be helpful to read the 'man' pages for these system calls.
|
||||
|
||||
1. You will be using the ```fork()``` system call to create child processes
|
||||
2. You will also be timing your code's executing using the ```clock_gettime()``` system call
|
||||
3. You will have to allocate a share memory segment using ```shm_open()```
|
||||
4. You will have to initialize the segment to the correct size using ```ftruncate()```
|
||||
5. You will have to map the shared memory into the process address space using ```mmap()```
|
||||
6. You will have to release the space at the end of your program using ```munmap()```
|
||||
7. You will have to delete the shared memory segment using ```shm_unlink()```
|
||||
|
||||
## The Exercise
|
||||
|
||||
Recall from linear algebra you can add two matrices using the following:
|
||||
|
||||
If A = [a<sub>ij</sub>] is an m x n matrix and B = [b<sub>ij</sub>] is an m x n matrix, the sum of A + B is an m x n matrix.
|
||||
A + B = [c<sub>ij</sub>], where c<sub>ij</sub> = a<sub>ij</sub> + b<sub>ij</sub>
|
||||
|
||||
The definition of matrix addition indicates a cell by cell addition. For each cell in A, the value is added to the value in the corresponding cell of B. To add A and B they must be the same dimensions.
|
||||
|
||||
Matrix addition is commutative. So, A + B does is always equal B + A.
|
||||
|
||||
Your task is to create two programs that will perform matrix addition for two matrices given to you as two files and print the result. Each program must also record the amount of time it took to perform the matrix addition.
|
||||
|
||||
- The first program will perform the matrix addition with a single process.
|
||||
- The second program will perform the matrix addition with multiple processes – one process for each row.
|
||||
|
||||
The format for each matrix file is:
|
||||
|
||||
- The first line will contain two numbers: the number of rows in the matrix followed by the number of columns
|
||||
- The rest of the file will contain rows of numbers representing the numbers in the matrix
|
||||
|
||||
For the example given above the file for A would be:
|
||||
|
||||
```text
|
||||
2 3
|
||||
1 10 0
|
||||
3 -2 6
|
||||
```
|
||||
|
||||
And the file for B would be:
|
||||
```text
|
||||
2 3
|
||||
1 4 0
|
||||
1 2 3
|
||||
```
|
||||
|
||||
All numbers in the file will be separated by spaces.
|
||||
|
||||
## Development: Single Process
|
||||
|
||||
It's simplest to break down the development into pieces:
|
||||
|
||||
1. Read the matrices
|
||||
2. Perform the matrix addition
|
||||
3. Print the result
|
||||
|
||||
### 4.1 Read the Matrix Files
|
||||
|
||||
A simple way to read integers from a file is to use the ```fscanf``` function. This function allows you to do formatted reading from a file. We'll use this to read numbers. To use ```fscanf``` you first must open a FILE* with ```fopen``` (take a look at 'man fopen' for more information). Then, like printf for printing a number you use the “%d” format as a parameter to ```fscanf``` to read a number. Here is an example:
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int value;
|
||||
FILE* input = fopen(argv[1], "r");
|
||||
fscanf(input, "%d", &value);
|
||||
fclose(input);
|
||||
}
|
||||
```
|
||||
|
||||
NOTE: the matrix file names will be given on the command line as arguments. For example: ./a.out matA matB
|
||||
Command line arguments are passed to main through the argc and argv values (see example above). The argc value tells the program the number of command line arguments, and argv is an array of character pointers for the argument strings. There is always 1 argument passed to your program (argv[0]) which contains the name of your program. So your matrix input files will be in argv[1] and argv[2]. If the user didn't provide enough arguments (e.g. argc != 3) then print an error and exit.
|
||||
|
||||
You can use this ```fscanf``` to read in all the numbers you need from the file. It takes care of all the white space for you. So, to read your matrix file you can start with:
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int rows, columns;
|
||||
FILE* input = fopen(argv[1], "r");
|
||||
fscanf(input, "%d", &rows);
|
||||
fscanf(input, "%d", &columns);
|
||||
for(int i = 0; i < rows; i++) {
|
||||
for(int j = 0; j < columns; j++) {
|
||||
int value;
|
||||
fscanf(input, "%d", &value);
|
||||
}
|
||||
}
|
||||
fclose(input);
|
||||
}
|
||||
```
|
||||
|
||||
Obviously, you'll need to store the row and column values somewhere. Since the matrix can be any size (within reason), you'll need to store the matrix in memory on the heap allocating a space for it using malloc. Remember that malloc creates a contiguous space in memory on the heap for the given size. Think about how much memory you'll need to malloc to store each matrix. When storing the values in the malloc'ed space you'll also have to do some math to make sure the indexing is correct.
|
||||
|
||||
### Adding the Matrices
|
||||
|
||||
When you store the matrices in the space created by malloc they are in one contiguous space in memory. So, to perform the matrix math, you'll also need to correctly compute the correct memory offset. Thankfully to access the memory at an index you can just reference it like an array:
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// malloc a space
|
||||
int* space = malloc(sizeof(int) * 100);
|
||||
|
||||
// Store data in the space
|
||||
for(int i = 0; i < 100; i++) {
|
||||
space[i] = i + 10;
|
||||
}
|
||||
|
||||
// Read data from the space
|
||||
for(int i = 0; i < 100; i++) {
|
||||
printf("%d\n", space[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
For this assignment, you'll just need to do the index calculation for the correct index based on the value's row and column. From there the calculation is just based on the matrix addition formula.
|
||||
|
||||
### Print the Result
|
||||
|
||||
It's probably easiest to store the matrix for the addition result in its own malloc'ed space. Once you have the result, you'll need to perform the index math to print out the matrix elements to the screen. For our example, that would be:
|
||||
|
||||
```text
|
||||
2 14 0
|
||||
4 0 9
|
||||
```
|
||||
|
||||
Print out each element in the rows and columns separated by a space. Don't worry about making sure they line up. You will also need to print out the amount of time it took to perform the matrix addition. For that you will use the ```clock_gettime``` function to get the ```CLOCK_REALTIME``` for the system before and after you do the matrix addition. You only need to record the time for the addition, don't include the time it took to read the matrix files or to print the result.
|
||||
|
||||
## Development: Multi-Process
|
||||
|
||||
Once you get your single process program working you'll follow the same steps for the multiprocess version, except that now you have use ```fork()``` to create a process for each row in the matrix element. Breaking this down into pieces:
|
||||
|
||||
1. Read the matrices
|
||||
2. ```fork()``` child processes to perform the matrix addition (one per row in the result matrix)
|
||||
3. Child processes perform the matrix addition for their given row
|
||||
4. The child processes write their results to the result matrix stored in shared memory
|
||||
5. The parent waits for all child process to finish
|
||||
6. Parent prints the result
|
||||
|
||||
NOTE: Recall that heap space is not shared between parent and child processes. So the result matrix is to be created in shared memory. Do this by creating a named share memory segment using ```shm_open``` and ```mmap```. Choose an appropriate name for the segment.
|
||||
|
||||
It is up to you to decide how the matrix is organized in the shared memory space. You can organize it as a one-dimensional array and use index calculation to find the row and column or as a two-dimensional array. However, remember that a shared memory segment is a single contiguous address range.
|
||||
|
||||
NOTE: Use only a single shared memory segment. Do ***NOT*** use a separate shared memory segment for each row.
|
||||
|
||||
### Read the Matrix Files
|
||||
|
||||
This is the same as the single process version
|
||||
|
||||
### Create child processes to perform the matrix addition
|
||||
|
||||
You will need to ```fork()``` a process for each row in the matrices. For our example above A + B has 2 rows so that requires 2 child processes. You'll need to ```fork()``` in a loop, make sure you keep track of the pid for each child process because the parent will need to wait for them to finish. Since you won't know how many processes you need when the program starts, you'll need to malloc a space to store the child process identifiers (pids).
|
||||
|
||||
### Child processes perform the matrix addition for their given row
|
||||
|
||||
Once you ```fork()``` the child processes you'll need to figure out how to make sure that each child process performs the matrix addition calculation each element in their given row. The formula for the calculation is the same as the single process version.
|
||||
|
||||
### Child processes write their computation to the shared result matrix
|
||||
|
||||
Allocated and mapped shared memory persists after a ```fork()``` system call so all child processes have access to a result matrix created in shared memory. The child processes can write their result directly to the shared memory space for the result matrix. The parent does not need to collect results.
|
||||
|
||||
### The parent waits for all child process to finish
|
||||
|
||||
The parent needs to keep track of all the process identifiers (pids) for all child processes and perform a waitpid for each one. This will require a loop and call to ```waitpid()```. See the man page for ``waitpid()``` for additional information.
|
||||
|
||||
### Parent prints the result
|
||||
|
||||
Once the child processes have finished, printing the result is the same as the single process program. Make sure the parent waits for the children to finish otherwise the result matrix won't be correct.
|
||||
|
||||
## Development Tips
|
||||
|
||||
- Remember that to successfully add two matrices the dimensions must match. So an m x n matrix can be added to an m x n matrix, but an m x n matrix cannot be added to a m x p matrix unless n == p. If the input matrices are not the correct size, print an error message to the user and quit.
|
||||
- Don't forget to free your mallocs! Remember that when a parent malloc's space on the heap, the child will get an EXACT COPY of that data. The child also inherits the responsibility to free the storage. Don't forget to free your mallocs!
|
||||
- Don't forget to ```munmap``` your ```mmap``` spaces! Remember that when a parent maps an address space, the children processes also gets that ```mmap```. The child must therefore ```munmap``` the address space AND close any used file descriptors when it is done. Don't forget to do this in your code!
|
||||
- Don't forget to close your file descriptors! When you call shm_open you get back a file descriptor. The children inherit file descriptors after a ```fork()```. All opened file descriptors must be closed by all processes when they are done using them (the parent too).
|
||||
- Don't forget to ```shm_unlink``` your named shared memory segments! Named shared memory segments are persistent (they live beyond the life of your process). Make sure you ```shm_unlink()``` your named shared memory segments. BUT make sure you don't ```shm_unlink``` before you need to. Don't remove a shared memory segment until you are absolutely sure that nobody else is using it!
|
||||
- Don't forget about using gdb to help with debugging (compile with -g to get additional debug symbols)
|
||||
|
||||
NOTE: when using gdb it is helpful to compile your program with additional debug symbols included. These allow gdb to show you more information when running commands like backtrace (bt). To compile with additional debug symbols use the -g flag on gcc. For example:
|
||||
|
||||
```text
|
||||
gcc -Wall -g -o myprog mysourcefile1.c mysourcefile2.c mysourcefile3.c
|
||||
```
|
||||
|
||||
- Using valgrind will be helpful in this lab to ensure you do not have any memory leaks.
|
||||
- When compiling your shared memory program you will need to include an additional compiler flag: -lrt. This tells the compiler to use the real-time c library where the wrapper function calls for the shared memory system calls. The examples use this in the Makefile, so you can see how to use it there as well. For example:
|
||||
|
||||
```text
|
||||
gcc -Wall -g -o myprog mysourcefile1.c mysourcefile2.c mysourcefile3.c -lrt
|
||||
```
|
||||
|
||||
NOTE: the -lrt flag must be the LAST thing on the command line. If it is not, your program will not compile.
|
||||
|
||||
## Testing and Debugging
|
||||
|
||||
There are [several matrix files](matrices.zip) located provided along with this specification. You can use those to help get your programs working. You are also required to create some of your own and include those in your submission. Don't forget to test large matrices.
|
||||
|
||||
## Deliverables
|
||||
|
||||
You will need to include all your source files and any other resources you used to complete lab.
|
||||
|
||||
A makefile is useful, but optional for this assignment. If you created a makefile, include it in your submission.
|
||||
|
||||
All files should be well documented with function comment blocks and inline comments that explain complicated code routines. While no explicit style guidelines are set for programming in this course, code should be documented and readable. Include your name, section, and lab name in a comment block at the top of each file.
|
||||
|
||||
NOTE: do ***NOT*** submit any IDE configuration files (.idea, project files, etc.). Only submit your source files.
|
||||
|
||||
NOTE: You should ensure that this program compiles without warning (-Wall and -Wextra) prior to submitting.
|
||||
|
||||
Prepare a zip file with all submitted files and upload the file to Canvas per your instructor's instructions.
|
||||
|
||||
## Grading Criteria (100 Points)
|
||||
|
||||
Demonstrate that your lab is working by compiling it, running it, and running any test code in person during lab hours.
|
||||
BIN
04-MatrixAddition (pthread)/a.out
Executable file
BIN
04-MatrixAddition (pthread)/a.out
Executable file
Binary file not shown.
3
04-MatrixAddition (pthread)/matrices/matA
Normal file
3
04-MatrixAddition (pthread)/matrices/matA
Normal file
@@ -0,0 +1,3 @@
|
||||
2 3
|
||||
1 10 0
|
||||
3 -2 6
|
||||
3
04-MatrixAddition (pthread)/matrices/matB
Normal file
3
04-MatrixAddition (pthread)/matrices/matB
Normal file
@@ -0,0 +1,3 @@
|
||||
2 3
|
||||
1 4 0
|
||||
1 2 3
|
||||
11
04-MatrixAddition (pthread)/matrices/matC
Normal file
11
04-MatrixAddition (pthread)/matrices/matC
Normal file
@@ -0,0 +1,11 @@
|
||||
10 10
|
||||
0 0 3 2 2 3 3 2 3 1
|
||||
0 2 3 1 2 2 2 3 2 0
|
||||
3 1 3 0 2 2 0 1 0 3
|
||||
2 0 1 3 0 2 2 1 0 0
|
||||
2 2 2 1 3 0 0 3 0 0
|
||||
3 1 2 2 3 1 1 0 0 3
|
||||
1 1 1 2 1 2 0 0 0 3
|
||||
3 1 2 0 2 0 0 2 3 1
|
||||
1 2 1 3 3 2 3 1 1 3
|
||||
3 1 0 2 3 2 3 1 1 0
|
||||
11
04-MatrixAddition (pthread)/matrices/matD
Normal file
11
04-MatrixAddition (pthread)/matrices/matD
Normal file
@@ -0,0 +1,11 @@
|
||||
10 10
|
||||
3 3 3 3 1 2 3 0 0 2
|
||||
1 2 0 2 4 1 4 2 2 2
|
||||
4 0 0 0 4 1 3 4 3 1
|
||||
2 1 3 1 2 3 1 2 3 4
|
||||
0 3 2 2 3 2 1 2 2 0
|
||||
2 2 1 2 1 1 1 4 1 4
|
||||
4 0 2 2 4 1 0 1 0 2
|
||||
4 4 3 0 2 3 3 4 0 4
|
||||
2 4 0 1 0 4 3 2 0 4
|
||||
3 2 4 4 0 1 3 3 4 4
|
||||
101
04-MatrixAddition (pthread)/matrices/matE
Normal file
101
04-MatrixAddition (pthread)/matrices/matE
Normal file
@@ -0,0 +1,101 @@
|
||||
100 100
|
||||
7 8 6 5 5 6 5 4 8 9 9 1 4 5 9 9 3 5 3 2 3 1 1 1 8 0 7 0 7 6 3 7 5 3 0 9 3 7 4 7 7 1 8 1 3 0 4 8 0 1 1 9 1 5 7 7 2 5 4 7 3 4 1 6 5 6 9 1 6 7 7 6 1 5 1 6 3 0 5 6 4 9 1 2 5 4 2 9 3 6 9 8 0 0 4 5 2 9 3 7
|
||||
8 6 5 4 3 1 7 2 7 7 8 1 9 7 8 6 3 1 0 5 1 4 7 3 7 8 6 7 8 5 7 1 0 0 1 2 5 6 9 1 1 6 7 1 7 5 0 6 3 5 6 0 0 7 8 0 3 4 0 3 1 1 3 8 6 6 9 6 0 6 7 4 2 3 2 6 7 8 9 6 3 2 2 9 0 8 2 1 9 1 2 7 2 9 6 9 2 1 0 7
|
||||
6 6 8 6 4 1 1 0 9 4 9 5 9 0 4 1 1 8 5 9 5 8 2 2 0 9 6 1 5 1 4 2 6 1 5 9 9 6 6 0 0 8 7 8 1 2 6 8 0 8 1 0 5 0 8 1 4 9 4 2 0 2 5 6 3 9 7 3 6 7 8 8 1 5 4 0 5 3 4 1 5 6 4 3 5 4 4 1 6 1 8 3 6 0 0 0 6 2 4 8
|
||||
4 7 1 4 9 6 6 2 7 2 3 1 5 5 1 4 6 8 5 9 8 3 6 8 5 4 6 1 7 9 9 7 7 5 6 8 6 7 3 1 1 6 9 3 7 9 0 9 4 3 7 1 2 0 3 9 5 6 4 7 1 3 0 0 4 6 2 9 7 5 0 6 0 6 0 8 8 8 5 9 9 6 0 4 2 1 9 3 2 7 0 4 1 5 3 1 3 4 3 2
|
||||
1 7 4 7 9 0 9 1 5 4 1 3 3 2 7 7 3 8 4 9 3 9 5 3 9 5 0 1 3 0 8 5 0 1 2 6 2 6 4 9 3 8 5 2 5 0 0 0 8 0 1 6 7 3 9 1 1 5 9 5 1 8 8 6 0 7 1 8 6 2 8 6 2 6 3 5 8 4 6 4 4 8 1 3 3 4 2 7 9 1 5 2 1 7 4 2 1 3 3 8
|
||||
2 6 9 2 4 7 0 3 7 8 9 5 3 5 2 0 2 3 8 4 2 5 9 2 2 8 9 3 8 5 2 2 8 0 1 6 8 6 6 6 1 4 1 7 0 2 4 5 0 4 7 0 5 2 1 7 2 4 4 0 4 9 2 1 8 3 5 6 8 4 4 7 5 6 2 7 9 9 6 0 0 4 1 3 4 0 6 4 0 5 5 1 2 0 9 8 0 6 5 5
|
||||
6 2 3 2 1 8 4 9 2 7 6 2 9 9 5 1 6 0 6 1 2 6 2 9 8 7 9 4 8 6 2 4 8 2 5 2 1 0 0 3 0 4 0 8 9 0 8 3 0 7 0 7 0 2 2 7 4 8 9 1 0 3 6 7 1 5 3 5 3 0 5 5 2 5 0 4 8 9 5 0 3 4 2 0 3 2 0 4 3 9 7 6 4 0 3 5 2 8 4 8
|
||||
5 3 1 1 6 3 6 0 0 8 8 3 1 8 9 1 8 0 4 6 5 0 1 5 8 8 2 1 0 0 2 8 3 3 9 4 6 1 3 9 2 1 6 7 9 4 8 6 6 6 7 1 1 3 4 4 3 8 3 6 3 4 8 4 5 3 1 8 4 7 6 3 0 3 6 5 8 0 7 4 9 2 9 3 2 1 3 6 2 5 6 1 4 5 2 9 7 4 2 7
|
||||
3 2 7 2 4 0 7 2 0 3 0 4 2 5 5 6 7 0 7 8 2 7 0 1 8 3 6 6 2 3 5 8 5 9 9 2 3 4 6 0 9 7 8 2 2 2 9 2 5 3 1 1 5 1 6 1 8 3 9 1 4 5 7 7 1 6 0 5 4 3 1 8 5 4 9 0 0 7 4 3 8 9 5 3 0 9 5 9 1 3 8 5 7 0 0 1 1 0 9 9
|
||||
6 4 4 5 8 0 9 2 4 5 7 9 0 8 7 0 3 2 5 6 4 7 5 7 6 0 4 8 0 0 3 1 5 8 1 2 4 1 3 6 4 0 2 8 9 3 3 3 0 3 7 9 2 2 2 1 1 8 0 8 1 6 7 6 5 7 3 7 9 0 8 1 4 8 7 9 9 4 3 2 6 8 8 5 8 7 2 7 9 6 9 8 6 6 9 9 5 6 5 6
|
||||
7 3 2 2 3 2 9 4 0 7 0 5 9 8 7 5 5 4 6 4 1 1 7 4 9 0 5 5 1 1 4 3 0 4 0 5 3 9 8 6 1 5 7 2 1 2 7 1 1 5 7 9 2 9 2 0 4 3 0 3 4 0 7 4 1 8 3 0 4 6 7 4 6 9 8 4 0 7 9 6 4 0 0 2 7 9 8 0 2 1 3 1 7 8 2 9 4 7 4 6
|
||||
9 0 4 2 5 4 7 3 3 0 4 7 8 4 1 0 8 0 4 7 4 6 4 4 2 2 7 4 2 9 2 8 8 2 3 2 6 7 2 0 0 6 4 4 0 7 6 3 3 7 2 4 8 2 0 8 1 1 7 1 3 3 1 7 6 2 0 1 9 5 3 1 1 4 8 1 7 1 5 1 1 3 3 0 5 0 4 9 5 8 5 7 8 6 6 5 4 1 6 7
|
||||
8 1 3 5 6 0 5 9 2 9 8 1 9 6 0 8 4 1 1 6 5 0 6 8 3 1 0 6 2 3 3 9 5 4 7 7 9 7 1 7 4 5 0 2 0 2 4 0 5 3 6 3 5 8 0 2 0 1 4 4 6 1 2 9 2 5 9 1 6 9 7 6 1 6 1 9 6 1 8 6 9 7 6 8 1 7 4 9 2 9 9 5 7 5 1 0 4 5 4 7
|
||||
1 2 1 6 2 6 5 9 3 9 8 3 2 2 7 4 6 2 9 2 7 6 6 3 1 4 4 9 0 8 1 0 1 0 0 0 9 5 4 6 6 5 7 4 0 9 7 6 9 1 8 3 7 2 2 5 3 1 0 9 3 0 6 8 4 3 0 0 3 9 4 7 0 5 1 8 7 4 6 6 8 8 6 4 6 4 8 1 9 9 8 4 0 3 5 0 1 3 9 4
|
||||
7 2 0 1 4 2 2 9 9 2 8 9 0 2 5 5 7 0 1 0 6 3 9 4 4 6 5 3 0 4 8 5 2 0 8 1 2 7 5 8 3 1 3 3 3 9 7 1 5 8 6 4 3 1 3 3 6 9 8 3 1 5 2 2 5 0 5 7 8 1 6 0 5 4 6 8 8 0 0 1 2 2 4 2 7 6 1 9 7 5 8 6 9 7 8 6 2 8 0 0
|
||||
6 0 3 5 8 2 0 6 8 7 6 5 8 9 0 1 2 9 9 8 5 4 7 2 0 0 5 0 8 0 9 1 0 5 5 3 9 6 3 9 0 4 7 2 5 7 3 4 0 3 0 2 7 2 2 9 3 6 8 5 6 2 7 7 1 3 6 2 0 1 2 0 7 4 6 0 4 8 0 6 5 6 3 3 8 6 0 4 6 9 5 8 3 2 4 1 2 2 7 5
|
||||
6 4 1 8 6 5 8 0 3 5 5 4 8 7 6 5 0 4 9 0 2 3 1 1 6 2 6 1 0 2 7 6 9 7 9 1 3 1 2 5 8 9 6 9 3 1 1 1 1 6 6 8 9 6 1 5 3 8 0 4 7 3 1 7 8 3 8 6 8 5 3 4 1 3 1 5 4 3 7 1 4 4 9 9 8 4 6 2 3 8 6 6 3 5 0 9 1 4 5 4
|
||||
6 9 8 9 7 7 1 5 0 5 6 5 9 4 9 8 5 2 9 0 5 0 4 3 6 7 7 6 9 7 2 7 3 1 2 6 3 1 6 1 9 8 2 8 5 5 4 4 3 6 1 4 4 9 7 6 8 0 4 9 8 7 1 7 6 3 1 1 2 9 5 8 6 5 2 4 7 4 7 1 8 9 7 9 6 7 4 0 8 3 8 1 3 3 7 8 7 1 7 7
|
||||
4 4 5 9 4 5 1 6 8 8 1 6 9 5 9 1 7 7 3 8 2 3 6 7 0 4 1 0 0 4 7 9 7 9 0 5 6 3 4 5 8 8 7 5 4 2 4 4 2 6 7 6 3 6 5 4 7 2 3 1 9 4 8 8 5 6 9 1 7 6 7 3 9 3 1 7 5 8 2 7 9 7 0 0 1 1 2 2 3 4 2 6 2 0 1 6 3 6 5 0
|
||||
5 9 8 4 7 4 3 5 9 5 3 2 4 1 5 1 7 6 6 1 1 9 9 3 8 3 4 6 6 6 1 0 6 9 8 1 9 6 7 5 5 0 9 5 0 3 6 1 2 9 2 3 3 0 7 2 0 2 9 6 9 8 7 9 4 2 1 7 4 7 0 6 9 3 5 6 7 7 2 4 4 6 6 4 4 9 3 4 6 6 3 7 7 5 0 0 1 7 0 5
|
||||
7 8 9 1 8 6 8 0 2 3 9 8 7 1 8 2 4 2 1 3 4 1 0 7 6 5 7 6 0 0 8 2 3 2 0 0 3 2 8 2 4 4 6 7 7 4 4 5 5 1 0 0 8 4 3 4 7 9 1 7 5 8 3 0 9 1 5 7 2 3 9 0 6 3 5 6 4 9 4 9 2 8 9 9 2 7 2 2 0 1 1 8 5 7 1 1 3 6 9 9
|
||||
8 6 6 7 0 1 1 3 3 8 4 6 4 4 4 7 1 4 3 0 8 3 5 3 9 7 7 3 2 2 4 1 6 5 7 2 2 3 0 3 2 2 5 9 4 6 5 7 6 9 3 7 6 2 5 5 3 7 2 0 9 0 1 1 4 6 4 6 4 0 1 7 8 9 5 3 6 9 0 5 5 2 5 4 5 6 4 2 6 6 2 0 9 7 0 0 6 4 6 7
|
||||
7 0 4 0 4 0 9 2 0 6 7 2 3 2 1 9 3 4 0 2 2 2 9 6 3 7 6 1 3 6 3 8 6 6 1 1 5 4 9 6 4 0 3 9 4 7 6 0 2 1 5 5 7 6 0 6 4 4 9 8 8 4 6 7 4 9 5 7 3 8 3 3 7 8 0 5 2 0 5 1 4 8 9 2 7 6 5 7 7 0 3 9 3 0 4 7 7 5 6 7
|
||||
7 6 3 6 7 3 0 0 1 2 9 2 6 8 9 5 0 0 9 4 9 9 9 6 8 2 5 0 3 7 6 0 0 2 2 7 7 3 2 6 7 4 6 6 6 2 5 9 2 7 4 9 9 0 0 7 9 0 2 3 1 0 5 4 9 8 6 3 1 9 5 1 8 1 4 3 7 6 0 8 9 8 6 8 2 7 0 2 9 3 7 3 5 5 4 3 7 4 7 3
|
||||
2 7 4 5 9 4 6 9 2 2 4 1 3 4 1 2 2 0 3 3 5 2 9 6 3 8 1 0 9 4 4 4 5 1 8 9 1 8 9 8 0 8 9 2 3 5 1 4 0 0 9 5 4 7 7 6 6 9 4 5 4 1 7 0 9 9 4 4 0 4 9 4 7 4 6 0 9 1 2 9 2 4 1 4 8 8 0 0 9 5 5 2 0 5 9 4 0 1 0 7
|
||||
1 9 7 0 3 6 8 0 2 4 2 0 7 2 2 0 4 3 2 1 8 7 7 9 1 0 8 9 9 5 7 1 6 6 6 2 7 8 2 5 1 3 8 6 8 7 8 1 2 3 3 6 5 6 4 2 6 0 3 2 3 5 9 3 5 2 2 9 1 1 8 2 7 3 8 3 8 4 3 9 6 2 2 7 4 7 2 7 5 7 8 0 3 5 8 4 0 9 0 6
|
||||
9 9 7 1 3 5 9 7 1 2 0 3 7 2 3 0 9 9 0 3 8 4 5 9 6 3 5 4 6 0 2 0 2 1 9 6 0 1 2 3 4 7 6 1 4 8 5 4 0 0 7 4 2 1 4 1 1 2 4 9 7 0 3 5 8 9 1 0 7 2 3 8 9 6 3 9 8 7 7 3 6 8 0 7 9 3 6 8 7 8 1 3 0 4 4 2 7 9 4 6
|
||||
9 0 9 9 5 7 9 6 9 7 2 6 7 8 3 9 1 7 1 3 6 8 3 8 1 1 3 3 4 7 6 0 6 3 3 1 5 3 4 2 6 2 1 3 9 2 3 4 2 8 1 7 4 6 7 3 9 6 5 3 8 5 3 7 9 9 5 8 5 6 2 3 0 8 5 8 6 3 8 3 8 7 3 6 3 2 1 7 3 9 7 4 4 5 4 6 1 5 2 6
|
||||
3 1 6 0 8 9 6 0 5 1 9 7 7 3 6 9 8 8 8 7 6 0 1 5 9 5 7 6 7 5 2 3 5 5 4 7 7 2 7 4 7 6 4 5 9 0 6 9 7 4 1 8 2 0 0 9 2 1 4 8 0 1 8 4 9 1 1 9 0 8 3 8 8 2 0 5 7 6 3 9 3 3 9 5 8 3 1 3 7 6 9 7 4 4 8 7 2 4 1 1
|
||||
6 0 2 3 7 6 3 3 5 4 5 9 0 0 7 7 5 2 5 9 9 4 4 1 6 7 2 9 7 2 0 6 4 1 0 4 8 3 1 8 4 7 1 3 0 8 2 5 3 2 4 6 4 9 2 8 6 3 1 5 2 3 8 5 9 5 8 6 1 3 0 6 5 5 9 8 6 5 2 8 7 8 5 4 7 1 1 1 6 4 5 2 0 7 2 7 5 5 7 3
|
||||
4 5 2 6 5 8 9 1 7 2 5 1 6 1 5 5 4 1 8 1 4 8 1 7 7 5 3 1 5 9 5 1 1 3 1 2 8 1 8 3 0 9 4 9 8 1 6 7 6 8 2 9 3 0 1 3 9 1 6 0 7 4 1 3 3 8 8 8 4 0 0 9 6 5 9 2 2 6 7 3 8 3 2 0 7 5 2 3 2 5 7 8 3 8 1 7 4 7 5 8
|
||||
1 8 3 0 5 1 6 0 7 1 2 8 2 4 2 6 3 2 5 0 1 5 1 1 2 6 8 6 4 8 3 8 0 8 6 1 3 6 2 4 0 8 2 4 9 3 4 7 8 9 1 1 9 5 6 2 1 7 4 6 9 3 9 2 8 1 5 4 2 9 9 0 3 8 4 8 1 7 0 3 9 1 6 1 6 8 4 2 8 9 5 2 1 9 3 7 9 8 5 9
|
||||
7 2 7 0 2 3 6 4 3 7 2 7 7 6 4 7 0 3 8 6 8 4 8 5 0 9 4 5 1 6 4 8 5 2 6 1 3 6 1 5 2 6 7 6 0 5 8 3 4 5 8 5 3 6 9 8 4 2 5 1 1 9 5 0 4 8 5 7 4 6 5 8 1 5 1 5 1 0 3 0 6 2 9 8 9 9 6 1 4 3 1 5 4 5 0 2 9 4 2 1
|
||||
4 6 3 2 5 8 1 2 2 0 5 6 3 3 5 2 5 8 2 2 8 0 7 8 4 6 0 5 3 6 9 8 9 7 4 9 3 1 9 9 8 9 6 2 1 8 4 3 1 3 1 6 5 3 6 6 0 5 1 3 8 2 0 1 1 0 5 7 0 4 7 5 7 5 1 2 6 9 0 3 3 1 4 1 4 8 1 0 6 1 1 4 5 4 0 0 2 9 1 9
|
||||
8 2 2 5 0 7 7 8 2 0 7 0 6 8 0 7 2 6 4 3 3 9 9 8 7 2 3 0 4 4 7 3 4 4 8 1 5 7 2 7 1 0 9 3 9 9 4 4 9 2 8 1 7 2 4 7 3 9 6 1 4 9 9 1 6 5 6 7 2 6 0 4 9 9 1 6 2 8 1 5 6 1 8 4 5 3 0 9 2 8 8 1 8 1 7 0 9 5 5 2
|
||||
9 1 2 8 2 0 8 0 6 2 9 2 3 1 6 2 6 0 2 7 4 0 6 4 9 5 9 1 2 1 3 5 6 6 6 6 9 8 4 0 9 0 0 9 7 5 7 0 9 9 6 1 5 5 5 7 2 9 3 5 2 8 6 7 1 4 9 5 7 9 0 6 2 2 9 9 2 6 2 7 9 6 1 5 5 7 2 9 3 8 8 0 9 7 4 0 9 3 8 8
|
||||
5 9 9 1 0 4 9 7 0 0 9 2 6 3 8 4 1 7 2 4 7 8 9 6 3 8 3 5 7 1 6 7 5 2 2 7 0 2 4 6 0 1 1 0 0 4 7 5 8 3 2 4 9 5 9 5 7 5 0 8 3 4 3 6 9 9 2 8 8 1 7 5 4 2 9 4 3 7 6 4 5 3 2 5 5 2 9 2 7 4 1 3 4 3 1 6 6 2 3 7
|
||||
0 8 2 0 6 7 6 4 4 6 2 9 2 9 5 7 4 4 7 0 7 5 3 8 9 7 6 0 2 2 1 4 7 6 6 1 1 0 6 3 0 6 9 6 9 9 9 5 6 4 1 0 1 2 6 7 4 4 1 4 2 7 6 8 0 5 5 7 0 1 8 1 9 5 6 7 5 4 0 1 8 0 0 7 0 5 9 4 9 1 6 0 1 3 5 1 3 6 7 4
|
||||
4 3 9 2 7 7 5 9 0 4 5 9 7 1 1 7 5 3 8 2 8 6 3 8 0 2 1 8 1 5 5 5 3 9 5 3 2 2 2 9 1 2 7 4 5 0 5 5 8 0 7 8 5 7 3 7 6 4 9 2 0 5 7 1 6 6 8 4 2 8 9 6 4 4 6 7 9 1 9 8 6 0 5 3 3 8 3 8 4 7 5 8 2 5 9 9 2 5 5 7
|
||||
3 1 3 8 2 6 7 2 0 1 0 5 6 2 2 2 5 9 3 7 9 4 2 6 3 5 6 2 3 2 6 2 2 9 7 6 3 6 7 8 8 9 5 8 8 0 9 1 1 4 4 0 8 3 7 3 1 0 9 6 7 9 4 8 9 3 3 3 6 1 3 0 3 3 9 5 3 3 7 5 8 3 5 4 5 5 7 5 8 3 9 3 0 6 0 7 0 6 5 2
|
||||
7 1 9 7 0 8 8 0 2 6 4 8 5 5 2 7 3 6 9 8 8 2 6 4 9 1 1 2 5 9 1 9 9 9 5 7 2 8 0 0 1 6 5 1 2 3 2 5 2 9 6 7 5 1 4 0 8 2 6 7 8 1 0 0 3 3 8 0 4 4 2 3 1 2 3 3 0 1 8 6 2 3 2 9 5 0 3 7 5 9 9 5 9 6 9 5 7 6 7 4
|
||||
7 8 0 0 6 0 0 4 6 3 6 6 1 6 5 2 4 8 9 8 1 0 4 7 1 4 9 8 5 3 2 4 9 0 2 2 3 9 3 8 2 3 7 6 1 9 4 3 5 2 0 7 7 0 5 7 9 7 6 6 2 6 7 3 5 2 5 2 7 5 1 7 4 0 3 0 7 5 2 9 7 6 3 8 0 2 5 6 9 6 4 4 8 1 7 0 0 2 6 8
|
||||
5 9 6 9 3 1 8 8 7 7 5 9 8 6 1 2 2 5 7 6 9 2 4 8 6 2 1 4 7 5 3 1 1 6 0 9 5 0 2 6 8 3 5 7 3 9 6 3 7 9 1 8 4 0 4 7 5 0 1 0 2 7 8 2 8 4 9 9 7 2 8 3 8 8 0 7 4 1 6 1 3 5 3 9 8 9 2 1 2 5 9 3 8 4 3 8 5 8 0 8
|
||||
2 8 6 2 9 9 1 5 9 4 3 8 5 3 0 3 8 0 1 8 9 0 5 6 2 5 4 5 9 6 8 6 0 4 4 2 7 5 6 3 8 6 8 8 9 5 8 9 9 2 4 8 5 5 7 4 5 1 2 5 5 7 0 1 2 8 8 6 3 9 4 7 6 6 1 7 7 7 7 7 6 3 6 3 7 1 1 1 6 7 2 8 5 4 6 6 8 9 0 8
|
||||
2 6 5 5 5 7 5 6 8 3 0 2 3 5 1 2 0 8 1 7 2 1 6 5 5 6 2 6 9 9 3 7 6 5 1 6 8 5 6 6 0 1 9 6 0 7 9 4 9 4 7 0 7 8 3 6 0 1 1 3 9 7 2 1 9 6 0 2 1 6 4 2 1 1 4 7 5 5 0 2 2 3 8 4 6 0 2 2 2 8 7 4 8 2 9 5 9 3 6 0
|
||||
9 5 2 6 8 5 8 7 9 1 4 5 0 7 3 2 9 6 5 4 1 5 9 1 8 3 5 7 3 4 2 5 1 1 4 6 6 6 4 2 5 5 4 9 2 9 3 0 4 0 3 0 1 2 4 8 8 8 4 9 0 7 0 3 0 1 2 6 6 7 9 3 8 0 1 7 2 4 3 1 3 4 7 3 1 8 8 1 0 3 2 9 2 5 9 7 9 6 0 2
|
||||
3 9 8 4 7 5 2 8 5 6 0 3 4 3 0 1 0 4 3 7 2 5 4 6 2 6 6 4 1 9 3 6 9 4 6 2 9 3 1 2 8 6 0 2 5 1 1 8 7 3 4 1 7 5 7 2 7 7 0 6 8 0 2 9 7 3 4 4 5 0 3 2 7 6 3 0 8 0 0 7 6 4 8 3 1 1 5 0 4 3 9 4 3 6 0 6 0 4 2 8
|
||||
9 8 9 8 8 6 5 7 6 1 6 7 3 1 3 9 5 6 6 4 8 8 0 9 0 8 9 9 4 4 6 7 0 0 2 2 3 0 6 9 3 9 2 3 2 8 3 3 8 0 8 7 1 3 4 7 6 8 8 7 9 2 7 2 5 7 1 7 8 7 1 1 8 5 0 9 2 6 2 5 2 1 4 6 5 8 7 7 2 8 1 0 4 4 3 8 8 0 7 7
|
||||
4 6 9 1 6 8 4 7 7 6 5 0 5 8 3 3 6 5 9 3 4 1 9 7 6 4 0 2 4 9 2 8 3 1 9 5 6 7 0 8 2 9 8 8 9 7 5 2 0 0 3 2 4 5 6 2 6 5 9 3 3 8 5 1 1 9 1 0 6 0 8 3 7 2 0 9 9 6 6 3 2 9 7 5 4 6 0 7 9 6 5 3 6 5 9 4 0 6 3 7
|
||||
4 2 2 8 9 5 4 0 4 1 3 9 1 9 5 4 7 4 0 1 9 7 1 1 1 5 5 4 5 9 2 8 6 8 2 3 3 1 7 7 4 5 8 4 2 8 6 7 1 1 6 4 1 8 9 5 0 8 0 2 0 6 7 2 8 1 3 8 1 2 9 9 4 6 6 1 4 4 0 4 9 8 7 7 2 5 4 8 4 7 9 0 0 0 8 1 0 2 1 9
|
||||
2 0 3 0 8 5 5 2 8 6 2 7 9 6 5 1 0 8 9 5 3 2 9 0 5 2 4 0 1 5 2 7 4 7 9 9 8 0 0 6 4 1 6 5 2 4 8 4 2 7 3 4 2 3 4 7 5 6 8 8 4 6 1 5 4 6 8 8 4 4 2 2 1 4 5 0 0 9 7 6 4 1 8 6 0 1 6 8 3 1 8 3 1 7 1 1 1 9 3 8
|
||||
4 7 3 1 3 1 5 2 0 1 8 9 2 0 3 5 6 7 7 1 9 5 8 0 6 0 5 6 6 2 9 9 2 5 6 2 5 7 1 4 4 2 6 6 9 6 3 8 8 5 6 3 4 6 4 8 1 9 0 3 8 7 6 3 9 0 7 0 2 2 9 8 1 3 8 6 2 9 6 7 7 5 0 6 9 8 9 2 8 8 4 3 1 4 2 9 5 2 8 9
|
||||
3 6 8 7 2 6 1 7 6 8 1 0 7 9 8 4 3 4 1 5 9 0 6 6 4 7 1 6 8 7 5 0 6 1 1 0 5 6 5 3 1 9 7 8 1 8 1 3 1 3 0 3 5 6 5 1 1 9 5 5 7 0 1 9 6 3 4 1 5 9 0 9 2 7 3 3 6 2 4 2 8 7 9 6 3 4 9 0 9 5 1 8 5 0 1 4 0 3 6 1
|
||||
0 3 5 5 8 7 3 2 4 5 8 3 8 3 8 1 4 8 1 9 4 8 8 5 2 9 8 8 9 8 7 4 3 1 7 8 3 6 2 5 8 9 2 7 5 1 4 4 3 6 7 0 7 1 0 5 2 2 1 6 4 1 1 0 2 5 5 3 8 9 5 0 5 4 8 6 4 6 1 1 9 4 7 4 2 8 9 0 6 9 3 0 6 4 1 5 2 3 7 9
|
||||
5 9 4 5 1 0 9 9 8 4 8 7 2 5 2 3 8 0 1 4 0 3 6 4 6 5 1 6 9 2 4 1 6 0 7 9 6 6 1 3 5 1 1 7 6 6 5 0 8 8 3 8 7 6 5 6 7 1 3 3 4 3 2 2 0 1 8 6 4 8 6 8 3 8 8 5 6 5 6 3 6 7 5 9 7 4 5 9 5 0 5 0 4 6 8 1 6 7 2 5
|
||||
4 0 2 0 8 8 6 5 2 0 7 9 9 4 0 6 6 9 9 7 8 7 1 6 7 7 6 8 0 6 4 2 9 5 9 1 6 6 0 0 9 2 3 7 4 6 2 4 0 8 2 8 3 8 5 6 7 0 6 4 8 1 6 9 7 6 6 7 1 1 3 3 9 3 6 3 0 3 9 3 6 1 1 5 4 9 5 2 0 0 4 1 8 9 7 2 1 7 3 2
|
||||
3 7 0 5 1 9 9 0 5 8 1 7 2 9 0 2 0 6 9 3 6 0 6 6 3 8 9 9 3 6 6 6 8 6 4 9 3 3 6 7 9 0 2 2 3 1 0 1 5 2 4 0 6 9 1 2 1 4 1 9 9 0 4 3 7 9 4 9 2 7 8 9 1 7 0 2 2 6 7 4 8 9 3 4 1 2 5 3 8 7 8 3 2 0 6 1 7 4 3 9
|
||||
6 4 0 5 5 0 3 4 1 8 2 4 2 8 0 8 5 9 1 9 4 1 8 2 4 9 8 9 7 0 1 9 8 0 9 7 3 7 5 5 2 8 3 7 9 7 1 1 8 9 3 7 4 6 2 9 4 7 7 6 5 1 7 3 1 8 2 8 2 4 0 1 6 4 2 6 2 7 0 8 8 2 1 0 7 4 1 3 8 6 4 5 0 3 6 3 9 2 1 2
|
||||
0 1 7 5 2 0 8 3 4 7 9 1 8 3 0 4 4 2 0 5 7 9 3 6 8 6 4 4 5 5 6 1 4 4 0 4 8 2 7 3 3 0 4 9 8 8 4 1 9 8 4 0 9 4 3 3 4 1 3 1 2 0 7 1 9 6 1 9 5 0 4 1 4 6 0 7 6 3 3 5 8 8 9 5 9 0 4 6 4 5 7 8 3 0 0 4 0 1 6 2
|
||||
4 6 6 9 5 1 9 6 8 0 3 1 4 4 1 7 0 5 3 7 0 6 4 3 3 5 2 6 0 9 0 5 1 7 1 3 4 7 5 0 7 3 1 0 7 0 8 8 1 4 1 8 6 4 9 1 4 7 7 1 5 1 2 6 9 1 5 1 9 0 5 8 7 4 2 6 3 7 3 1 3 7 2 7 3 9 4 8 5 6 5 4 3 7 9 1 1 4 8 3
|
||||
8 2 5 8 7 2 9 8 9 7 2 0 8 0 6 2 9 3 1 0 1 9 1 8 1 6 6 2 0 0 8 1 6 8 3 8 0 6 3 3 1 4 8 8 8 2 0 0 0 9 4 7 5 2 5 1 0 8 0 9 0 6 3 4 6 2 3 3 8 5 9 0 7 3 7 2 2 3 5 3 8 0 6 6 9 6 4 4 3 5 4 3 2 5 3 0 5 9 2 5
|
||||
9 7 2 9 7 0 4 5 4 3 1 4 2 5 7 8 3 0 0 1 7 5 7 5 4 4 5 4 0 7 6 7 7 3 2 7 1 0 8 5 0 3 7 8 8 2 1 3 9 5 0 4 6 2 4 8 5 0 7 4 4 9 0 4 5 6 6 4 4 5 9 0 5 0 6 4 8 9 8 7 1 7 5 5 5 7 0 5 7 5 9 8 0 3 9 9 7 9 4 2
|
||||
5 1 9 3 3 5 8 7 6 2 9 9 6 0 1 5 0 0 7 0 2 8 7 1 3 2 4 8 2 2 4 9 4 0 6 3 9 4 1 8 1 7 4 0 2 8 0 0 0 8 2 7 2 9 6 6 3 9 8 0 5 6 5 9 3 8 1 1 3 9 1 8 8 6 9 2 2 9 6 3 8 1 9 0 4 3 4 7 8 2 3 9 7 3 1 4 4 5 4 3
|
||||
4 3 6 4 7 7 1 3 8 3 5 2 6 3 2 5 6 0 4 2 1 8 2 6 5 0 0 5 3 6 7 4 2 2 4 5 1 4 3 6 3 7 7 5 7 6 8 3 6 0 9 8 1 6 1 2 9 0 4 7 9 1 6 1 4 3 6 6 9 1 2 0 6 5 3 1 6 3 9 9 0 5 0 3 2 0 5 0 0 5 7 2 7 9 2 4 0 0 2 9
|
||||
1 5 1 0 1 2 0 5 0 6 2 2 7 2 7 0 5 1 2 4 4 7 7 2 4 2 4 5 1 5 3 4 7 1 4 1 2 1 6 8 4 5 6 5 0 2 6 2 2 3 9 6 6 4 3 2 7 7 1 1 3 9 3 4 5 6 0 0 1 8 2 2 8 7 7 7 8 0 7 1 5 7 6 8 9 6 1 5 0 1 9 4 4 5 7 0 5 2 6 7
|
||||
5 1 4 5 3 7 7 6 0 7 0 1 7 5 7 6 0 1 4 8 4 2 4 2 1 3 7 7 5 2 3 8 9 0 7 1 0 2 4 4 3 7 0 1 8 8 2 6 5 6 1 8 8 0 3 1 6 5 4 9 4 8 0 7 0 6 5 2 7 1 2 5 1 6 4 9 2 4 9 6 4 8 0 0 1 1 3 4 6 8 4 8 9 8 4 2 0 0 0 6
|
||||
7 8 6 3 2 7 3 5 3 7 4 4 8 9 5 9 1 2 8 7 2 0 6 7 4 8 9 5 4 6 0 9 1 0 4 9 7 4 9 3 6 9 7 1 8 9 0 7 7 1 9 6 5 1 2 1 0 6 1 4 7 0 4 8 6 1 4 4 5 4 3 0 5 6 9 9 9 4 4 3 4 3 2 5 2 1 0 0 1 0 7 7 4 4 5 9 1 0 3 9
|
||||
3 4 6 6 1 3 1 4 1 9 4 4 0 2 1 4 5 2 3 9 9 2 3 8 9 8 7 1 3 5 8 4 7 8 2 5 8 2 8 3 4 0 0 0 0 1 0 0 5 2 9 8 0 4 1 0 3 1 3 2 9 4 6 8 5 4 9 7 9 0 6 7 8 9 2 6 7 1 8 4 2 7 1 9 4 8 4 3 4 3 4 4 0 8 7 2 6 0 8 2
|
||||
4 7 6 6 7 3 8 4 5 3 0 1 3 1 0 0 4 7 8 9 4 5 2 3 5 9 7 0 0 3 9 3 8 2 8 9 2 0 8 7 3 0 8 8 3 5 1 7 3 2 6 6 1 0 8 3 9 4 4 1 8 0 9 4 1 3 8 7 8 2 2 8 6 4 7 8 5 8 7 5 1 9 5 2 1 0 1 5 5 7 7 1 1 3 9 7 6 1 7 9
|
||||
8 6 3 8 8 9 9 6 1 7 7 3 3 4 4 6 4 8 9 1 7 1 2 4 7 6 3 6 5 7 6 3 1 0 1 5 3 8 1 0 5 7 0 6 9 7 7 3 1 0 3 0 4 6 6 3 5 2 5 2 8 6 4 0 2 7 0 2 1 7 0 9 5 4 3 2 9 8 1 2 4 7 8 8 0 1 2 6 2 7 6 5 8 7 8 1 4 8 9 7
|
||||
3 9 6 6 0 0 9 2 5 7 9 5 5 8 4 6 3 5 1 7 3 4 8 2 9 7 8 5 1 1 8 7 1 0 8 7 3 9 4 7 3 9 3 9 6 0 2 3 3 3 1 1 9 8 7 8 2 8 6 9 4 9 0 0 3 8 4 3 6 7 9 8 9 1 0 9 2 7 7 8 3 3 7 5 8 5 1 3 9 7 3 4 3 9 0 2 6 8 3 6
|
||||
7 6 0 4 3 9 4 0 3 3 2 8 6 8 4 8 5 7 5 7 1 3 1 9 3 0 5 7 4 9 0 2 3 3 6 3 4 5 3 5 2 4 9 8 9 9 5 1 9 4 9 7 8 5 3 6 3 1 0 0 3 0 0 8 3 7 6 2 9 8 0 8 8 8 7 2 8 9 2 9 9 3 5 2 7 7 7 7 6 6 4 7 2 7 3 7 5 3 4 6
|
||||
1 9 8 3 4 4 4 7 6 3 6 6 7 9 1 9 9 2 3 0 7 0 4 0 6 2 6 8 9 7 8 8 7 4 4 7 8 8 1 5 0 1 1 1 2 2 7 5 6 6 3 8 3 6 8 7 7 6 2 9 2 5 3 3 7 9 9 1 2 4 6 4 4 8 2 5 9 4 3 4 5 2 4 6 4 0 8 9 4 3 7 5 5 1 6 4 4 1 1 4
|
||||
8 5 9 6 8 4 8 4 7 0 2 8 9 9 0 8 0 9 0 9 8 0 4 6 7 7 3 9 2 9 5 0 3 6 5 8 7 8 8 1 0 3 4 8 8 2 7 4 9 2 7 1 7 6 4 5 2 7 9 9 0 1 2 8 2 8 9 2 1 2 7 3 9 5 8 7 0 2 6 8 0 6 2 5 9 3 3 7 0 2 6 4 5 5 2 0 8 2 2 7
|
||||
9 6 6 2 9 5 3 8 7 3 2 6 9 6 1 2 1 7 9 3 1 7 8 1 1 9 3 5 4 6 5 2 2 6 4 0 5 0 1 6 8 0 1 4 0 4 1 2 7 0 2 4 7 6 7 9 1 5 6 1 9 0 0 5 1 5 3 8 2 3 9 8 6 6 3 0 6 0 2 3 6 7 0 9 1 6 9 2 9 5 5 0 4 3 0 5 0 4 6 3
|
||||
4 1 4 9 7 1 9 8 9 7 2 0 7 6 1 3 9 1 8 0 2 4 6 3 0 9 5 2 9 1 7 9 8 1 6 9 4 3 7 4 0 3 7 9 4 2 1 3 9 7 1 0 7 6 7 2 1 8 1 2 9 4 5 8 9 2 9 7 1 9 5 2 6 9 9 2 2 1 2 4 7 5 5 0 6 6 4 0 7 7 6 4 7 1 9 7 7 9 9 2
|
||||
1 2 3 9 9 8 6 9 6 0 5 5 3 8 5 8 2 3 4 2 3 7 2 8 4 0 0 7 8 8 3 3 6 9 5 8 9 1 0 6 0 1 7 5 9 6 8 9 5 8 2 7 1 6 7 2 3 5 7 9 8 7 3 3 1 7 7 1 3 4 8 0 2 1 4 3 3 0 3 5 1 4 5 5 1 9 2 7 3 8 5 1 6 3 0 3 5 3 9 5
|
||||
4 1 7 3 9 8 3 5 8 4 1 0 2 8 0 8 4 4 4 0 8 5 9 8 0 1 2 9 1 5 5 6 2 7 5 7 7 1 9 2 8 7 9 5 4 2 3 3 9 2 5 2 8 7 6 4 5 8 5 8 6 8 6 0 9 3 6 7 9 0 5 5 5 9 7 3 7 3 4 3 3 3 1 7 1 4 1 6 3 9 9 0 2 1 3 8 3 5 7 5
|
||||
3 4 9 7 4 3 6 3 7 6 6 1 8 0 7 9 3 7 3 8 6 2 0 7 9 0 5 6 7 2 3 9 2 3 8 4 0 5 4 3 5 6 5 2 6 7 5 6 1 4 9 9 0 0 2 7 4 3 9 4 7 1 2 6 0 1 9 2 2 1 9 2 0 6 7 2 7 8 8 2 5 0 8 6 1 9 6 5 7 5 5 3 5 7 1 6 8 9 2 9
|
||||
3 6 3 6 8 8 0 9 9 0 7 6 3 3 0 4 8 0 8 6 8 1 8 4 4 7 8 7 6 7 2 3 1 6 4 3 9 4 2 1 1 0 4 5 9 4 5 6 1 8 6 0 6 7 9 7 3 4 4 7 8 7 1 6 1 6 8 3 6 6 3 1 6 7 2 3 8 4 4 9 3 4 0 0 1 4 9 0 4 8 6 5 1 2 2 0 6 8 6 2
|
||||
3 0 5 3 9 1 6 5 2 6 4 4 8 5 0 7 0 7 0 1 7 2 6 7 3 7 1 0 1 8 1 2 2 5 3 8 0 8 2 0 6 4 5 0 9 8 8 5 2 4 2 9 7 5 9 0 0 3 7 2 4 7 5 8 3 2 4 7 6 5 8 7 0 4 5 0 2 6 8 5 5 2 9 1 7 4 8 1 8 7 9 2 7 5 0 2 9 3 0 8
|
||||
2 2 8 5 8 4 9 9 0 7 1 9 5 3 4 6 7 0 6 8 7 3 8 8 6 1 2 0 0 3 4 0 2 0 3 8 3 1 1 6 4 3 9 5 3 6 8 9 7 8 6 2 5 7 8 3 6 2 0 7 5 9 5 9 6 7 2 2 0 7 5 9 3 2 1 7 1 8 9 6 8 2 3 7 1 5 8 3 7 7 9 4 0 0 7 0 5 3 0 4
|
||||
6 0 1 7 5 9 7 1 4 9 8 3 8 5 1 8 5 5 0 1 8 2 4 7 3 2 1 4 6 6 8 2 7 0 5 3 8 7 1 7 6 9 4 0 3 9 2 1 0 7 9 0 0 8 0 8 5 5 8 6 4 0 4 8 0 1 0 7 1 2 5 6 5 3 5 3 8 8 1 2 7 9 2 3 9 5 6 5 9 5 6 0 7 3 6 4 3 1 6 7
|
||||
4 8 9 5 9 4 8 4 1 6 5 8 7 1 0 0 5 9 6 9 4 0 4 1 2 9 2 2 9 4 5 7 6 9 5 5 6 8 8 7 0 2 5 3 7 4 2 5 0 6 8 9 9 6 1 1 3 0 1 0 6 1 1 1 9 2 2 8 6 6 1 3 9 8 7 6 2 7 4 9 5 5 6 3 9 2 3 9 3 9 2 4 8 3 0 2 5 2 8 2
|
||||
8 1 1 6 1 9 8 2 5 0 7 0 4 8 1 3 7 8 3 3 6 9 3 6 5 5 5 3 6 1 4 8 7 7 2 6 8 2 0 7 0 4 4 9 3 2 3 9 1 5 9 1 1 3 4 9 1 7 7 4 7 7 9 1 3 7 8 1 5 0 0 0 2 2 2 7 1 1 9 9 7 7 0 4 8 7 1 2 2 2 1 3 8 6 5 3 0 7 5 3
|
||||
7 2 5 0 9 6 6 1 6 7 8 5 5 6 5 8 5 0 7 6 9 4 1 9 8 3 2 2 9 2 8 9 0 8 2 8 1 9 6 9 1 1 9 2 0 4 1 0 2 2 6 4 7 5 6 3 7 2 8 1 8 8 4 6 3 2 1 2 3 7 7 0 5 8 0 7 3 8 3 0 9 7 9 1 8 2 7 4 0 2 6 0 1 6 1 7 2 0 0 0
|
||||
7 3 0 2 2 0 5 1 0 0 1 5 6 9 0 3 4 8 9 1 6 8 3 0 6 5 2 6 7 5 2 3 5 5 3 6 2 4 0 7 1 9 2 3 7 8 4 8 1 1 5 6 9 4 1 5 4 6 5 5 6 2 0 1 6 8 3 8 1 8 8 9 8 6 9 9 3 2 4 9 5 5 3 3 7 6 8 0 3 8 0 4 9 1 8 5 8 0 0 8
|
||||
7 3 1 1 9 9 5 8 9 2 2 3 9 6 4 6 8 6 8 1 8 5 1 7 4 5 5 8 4 4 3 1 9 2 1 1 7 3 9 4 6 4 6 6 3 4 0 3 4 3 2 4 2 0 2 4 4 9 5 0 6 8 6 6 0 8 4 1 5 4 6 5 5 9 7 8 2 9 2 0 1 2 3 0 6 8 3 5 0 4 4 3 3 5 9 2 3 7 5 9
|
||||
6 8 5 2 4 7 2 4 7 5 8 1 2 4 4 1 6 9 5 9 4 5 5 8 3 1 8 1 3 7 6 8 3 1 3 0 1 0 1 5 0 7 0 9 8 1 7 5 6 2 9 5 0 3 5 5 9 9 7 2 5 1 2 7 7 6 5 3 1 4 1 5 0 8 1 3 7 3 9 4 2 0 3 8 8 4 6 4 7 5 1 5 4 0 2 7 2 0 4 1
|
||||
2 8 6 9 2 4 1 6 5 4 4 4 2 4 2 8 9 4 5 4 8 2 2 9 9 3 2 5 5 7 1 2 9 1 8 0 0 0 6 2 0 5 8 0 5 5 9 3 3 2 0 6 7 5 4 7 7 8 8 9 5 0 7 5 5 7 9 0 4 3 7 3 7 1 6 3 1 1 1 0 3 1 9 7 6 4 7 7 9 6 8 4 8 6 9 3 4 0 9 0
|
||||
8 5 3 2 1 7 2 0 6 2 4 2 5 6 6 1 6 4 4 1 2 7 7 2 1 6 9 1 7 2 7 2 0 1 2 3 5 2 9 6 2 5 5 8 0 0 9 9 9 7 4 3 3 9 8 2 5 0 6 6 0 0 3 5 0 2 3 1 4 3 4 5 8 3 9 0 1 1 3 3 4 7 9 8 2 8 5 2 3 4 7 4 0 9 0 5 9 5 9 9
|
||||
2 8 8 1 0 8 3 1 3 9 5 3 3 6 4 9 8 8 9 0 3 6 1 9 3 8 8 8 4 0 2 0 2 1 5 1 4 5 6 6 4 0 2 6 2 5 6 7 0 5 9 0 3 6 5 4 8 6 7 0 9 3 5 6 7 9 8 5 0 2 3 2 1 4 4 6 1 0 3 4 8 3 7 5 4 4 5 0 1 5 8 5 5 0 6 2 9 3 0 1
|
||||
1 2 8 7 0 9 3 5 9 2 1 1 8 0 4 6 8 3 8 1 1 7 5 0 3 4 0 5 2 6 7 8 4 7 2 0 7 8 3 9 4 1 3 2 6 9 5 5 3 2 2 0 9 1 6 4 9 9 7 0 8 4 3 6 5 4 8 2 5 4 2 1 7 3 7 9 6 8 4 3 8 6 1 9 1 5 5 9 9 1 0 1 6 5 3 8 3 2 5 6
|
||||
9 9 5 4 0 3 4 7 9 9 0 7 8 7 2 8 5 6 4 9 6 4 5 5 8 7 7 0 1 3 3 1 6 6 6 8 7 0 8 9 0 9 0 6 1 0 5 5 3 9 3 5 2 1 8 0 4 6 1 1 8 5 4 8 8 4 0 9 3 2 2 9 1 0 8 2 6 7 7 7 3 7 3 1 9 5 9 8 6 7 8 0 1 8 2 5 1 1 9 5
|
||||
4 7 7 6 1 5 7 1 9 5 8 7 2 7 9 6 9 5 0 7 7 9 3 7 4 8 1 3 4 2 7 5 4 4 5 4 7 9 2 0 5 9 9 1 7 7 6 9 4 5 7 9 0 2 6 7 0 3 5 1 9 6 9 4 1 6 8 5 9 0 1 1 5 8 7 8 9 6 8 8 1 4 0 7 8 9 0 1 1 8 7 0 0 6 4 6 0 4 3 1
|
||||
7 2 3 5 3 9 6 8 6 0 8 1 8 1 9 1 6 1 8 9 6 6 9 7 3 0 1 6 4 9 1 6 3 3 7 7 0 8 0 6 1 7 4 3 5 7 4 7 1 3 3 0 4 0 0 2 4 8 6 0 9 8 6 0 6 9 5 9 4 4 5 8 2 1 4 0 2 8 3 6 3 3 1 1 9 8 1 8 7 7 6 2 5 8 3 6 4 1 1 4
|
||||
0 6 9 4 6 2 4 1 8 8 6 6 0 2 0 0 9 0 0 8 5 2 2 7 9 2 8 5 1 7 2 7 6 5 7 4 1 2 4 2 7 8 6 6 0 5 5 7 0 8 9 0 6 9 1 7 9 3 3 3 3 9 4 0 3 9 4 1 7 3 2 8 9 6 2 5 5 5 3 4 9 8 5 8 8 6 9 1 1 2 1 1 3 0 9 4 4 0 7 2
|
||||
4 9 8 9 2 7 5 2 2 0 3 7 5 5 1 6 1 2 8 2 4 9 9 7 0 4 6 4 6 1 0 2 7 7 5 1 4 7 9 1 4 9 3 2 2 8 4 2 7 9 9 5 3 1 3 6 4 2 1 1 4 9 6 9 6 1 6 5 5 8 3 9 9 6 9 7 9 7 0 5 3 7 3 5 3 3 2 2 9 9 6 0 9 1 8 5 6 9 9 2
|
||||
3 1 3 3 6 8 8 4 1 0 4 2 1 8 9 7 2 8 0 9 6 8 2 0 2 5 0 5 7 0 6 0 0 1 0 7 6 0 9 4 3 1 6 0 3 9 2 3 2 2 3 6 7 1 3 2 9 3 7 0 3 7 0 2 2 1 6 4 2 3 6 0 9 7 8 4 9 1 9 2 4 7 9 6 6 8 5 4 8 6 3 6 3 2 9 0 5 3 9 1
|
||||
7 4 3 2 2 6 5 6 0 3 0 5 6 7 9 3 0 9 7 3 9 5 6 8 1 9 2 3 1 2 9 2 3 7 7 4 0 3 1 8 1 5 2 2 9 1 2 1 2 8 0 8 4 3 4 6 6 2 0 3 1 6 9 1 7 4 1 8 6 5 9 5 1 8 5 5 5 2 4 8 0 0 7 5 3 9 1 5 1 7 4 6 3 6 9 6 2 6 0 5
|
||||
101
04-MatrixAddition (pthread)/matrices/matF
Normal file
101
04-MatrixAddition (pthread)/matrices/matF
Normal file
@@ -0,0 +1,101 @@
|
||||
100 100
|
||||
5 5 3 7 1 8 3 5 2 6 6 8 3 9 8 3 5 1 2 9 0 1 2 5 2 4 4 7 0 0 9 0 8 2 7 2 1 1 4 8 6 7 2 8 1 7 0 3 6 3 3 4 2 5 6 1 0 6 5 8 2 5 1 0 2 6 4 2 8 5 9 4 8 2 2 2 8 6 2 7 1 2 1 7 1 4 7 4 6 4 3 8 1 5 7 6 0 7 7 7
|
||||
8 9 1 2 1 7 3 8 8 0 5 5 0 7 7 0 6 8 8 5 8 8 9 6 5 6 4 6 9 8 1 0 1 1 2 9 4 1 6 0 0 2 2 3 3 1 9 4 9 7 7 2 7 5 3 5 4 3 0 8 7 6 4 9 3 5 4 6 4 5 6 6 4 1 7 9 1 6 2 4 8 9 9 6 8 2 3 3 0 9 3 0 4 4 6 2 9 4 0 5
|
||||
0 9 5 6 6 1 9 6 5 7 9 2 0 3 1 2 6 4 3 8 6 1 7 6 3 6 4 9 0 0 4 0 5 3 7 3 1 9 0 1 2 3 1 4 5 3 7 9 7 0 0 0 6 4 5 9 2 2 6 5 3 1 7 8 4 9 5 4 6 0 8 8 1 7 2 9 7 2 6 5 7 8 0 1 1 3 5 2 8 6 1 9 4 2 4 9 4 7 6 1
|
||||
0 9 1 3 7 1 4 3 3 0 6 7 1 0 1 6 5 2 3 7 8 9 8 7 3 0 9 2 2 1 4 5 3 0 9 1 7 0 9 4 7 2 9 0 7 9 4 1 2 8 1 4 4 7 0 0 6 0 8 1 2 7 8 9 4 6 0 6 2 7 8 2 2 0 9 6 7 3 7 1 7 6 0 1 0 2 9 4 7 5 9 3 1 9 7 2 9 8 3 9
|
||||
3 2 2 6 4 4 1 9 2 3 9 3 7 8 3 8 8 6 1 6 1 0 2 0 6 1 0 2 7 5 3 8 4 6 0 9 5 2 5 5 2 7 4 9 1 2 1 0 7 1 5 4 3 5 0 6 4 5 0 3 7 9 4 3 5 8 8 3 7 3 7 8 8 1 4 1 2 1 4 5 5 4 2 3 0 9 5 8 9 9 2 7 0 0 3 9 8 4 7 6
|
||||
2 6 1 2 7 7 0 8 1 9 9 4 9 2 3 0 1 6 5 6 2 1 6 8 7 6 3 7 7 8 1 1 2 0 0 8 5 2 7 9 9 4 1 8 6 7 4 9 7 0 4 2 9 0 9 8 2 7 2 9 4 7 9 6 1 1 2 2 4 3 2 3 9 0 9 5 8 2 9 4 8 8 8 4 0 6 8 2 9 5 9 2 2 0 0 7 7 8 0 8
|
||||
9 9 6 7 3 0 1 1 5 4 1 0 0 6 5 7 6 9 7 1 7 7 1 0 7 6 1 8 7 8 5 9 3 8 8 0 0 8 1 6 0 4 0 9 6 4 5 4 1 8 4 6 6 3 5 0 1 5 5 9 1 0 4 9 5 4 1 1 2 9 5 4 0 4 6 8 4 9 7 0 9 9 9 8 0 6 7 3 2 7 7 6 9 0 4 7 2 1 8 6
|
||||
2 2 9 3 0 2 1 4 0 1 5 3 5 4 8 2 7 4 8 8 3 4 3 7 9 4 3 5 7 0 9 4 9 9 9 6 3 7 3 0 0 0 6 4 1 9 9 7 9 8 6 5 2 2 6 0 9 0 6 7 1 0 1 7 4 7 2 9 9 7 1 1 4 6 9 2 6 9 3 6 5 6 4 2 4 1 8 0 0 8 6 3 6 9 9 8 9 0 6 0
|
||||
5 0 6 5 2 8 6 0 8 8 0 6 0 0 7 4 9 9 8 0 9 7 7 2 8 8 3 4 8 4 1 1 4 4 7 9 8 0 3 5 6 9 3 7 5 2 6 9 5 6 0 1 9 9 4 7 2 0 6 7 8 1 5 8 1 6 4 5 7 0 6 6 3 6 6 7 7 0 8 9 1 8 5 9 1 0 1 3 6 5 5 1 1 6 8 2 1 4 9 0
|
||||
2 3 0 5 1 3 0 9 1 1 6 6 2 8 8 9 1 8 5 1 1 0 9 4 9 5 9 2 3 7 1 8 5 8 3 5 3 7 2 0 4 2 5 5 5 2 1 7 6 7 9 3 2 7 5 2 1 3 8 4 1 7 9 0 6 6 5 4 6 3 0 9 0 8 4 8 0 8 0 0 7 9 6 9 4 1 1 9 2 9 7 2 3 4 6 8 0 4 5 7
|
||||
3 0 9 8 2 7 3 3 4 4 4 8 3 4 9 4 3 5 3 2 4 1 0 1 0 4 9 2 6 9 8 4 8 3 7 4 3 8 0 4 9 5 4 2 1 2 7 8 1 1 5 7 2 7 0 4 4 6 9 5 0 6 7 6 7 6 4 3 9 7 6 4 4 9 0 2 7 2 5 8 3 5 0 4 2 5 0 5 6 9 3 2 7 3 9 1 2 5 0 0
|
||||
9 9 7 4 3 8 5 5 9 8 6 2 7 2 1 0 2 5 9 5 5 6 4 1 4 0 1 1 1 7 4 5 6 2 0 5 3 7 1 2 7 4 7 7 2 7 8 8 2 0 7 6 6 7 6 5 0 5 6 2 5 3 0 2 3 7 0 7 3 7 9 0 4 6 2 9 0 4 9 0 8 8 2 1 0 5 2 1 9 6 5 2 9 0 2 5 3 5 3 5
|
||||
3 5 3 2 2 9 3 2 9 4 9 1 2 8 9 3 1 8 9 0 7 3 5 5 9 5 3 3 0 1 2 0 4 8 7 3 3 3 6 7 6 7 5 8 4 8 0 4 6 8 9 7 3 4 3 0 6 4 2 8 0 5 2 0 8 9 1 2 1 1 1 0 1 5 4 6 5 5 4 9 9 9 9 2 2 3 8 6 4 7 8 8 9 2 4 1 3 1 9 0
|
||||
0 9 2 3 5 3 5 5 4 4 2 2 5 6 0 4 2 7 8 9 1 8 2 1 0 3 4 6 2 5 8 9 1 1 1 3 1 8 4 7 4 8 2 2 4 9 5 9 2 1 2 1 7 8 2 4 9 1 6 1 6 8 0 0 2 6 0 1 4 2 2 7 4 6 2 3 8 3 0 4 9 7 1 5 5 0 0 0 4 7 3 7 9 3 4 6 5 6 8 4
|
||||
1 2 2 9 2 4 3 0 9 7 4 3 1 3 0 1 2 9 7 5 9 8 8 1 7 1 9 6 3 1 2 8 7 0 0 5 5 6 1 6 6 8 8 9 2 8 6 5 7 0 7 1 0 9 6 1 1 7 8 6 6 7 4 6 5 1 4 0 6 0 8 9 7 6 4 6 8 4 1 0 5 2 5 5 3 7 9 8 6 2 1 7 5 3 2 5 0 5 4 5
|
||||
0 0 0 5 1 5 6 1 9 0 4 7 7 5 8 9 8 6 9 3 6 3 8 3 3 1 2 0 7 3 0 7 0 5 9 2 8 3 0 5 4 0 8 8 1 7 5 7 0 9 3 1 4 8 3 0 0 5 9 7 5 6 3 2 0 9 4 9 4 5 3 1 2 6 5 6 6 2 9 3 6 4 1 7 5 9 4 1 4 5 4 0 5 4 0 9 7 5 8 5
|
||||
5 1 0 9 9 7 0 7 9 6 8 7 2 8 4 0 5 0 7 3 9 8 0 0 1 9 3 5 8 7 4 8 8 2 4 6 4 6 0 9 4 5 2 2 5 7 9 6 1 1 3 2 9 9 2 9 7 7 7 6 9 6 4 5 7 3 0 1 8 7 6 5 4 4 4 3 1 2 1 1 9 2 2 6 5 1 2 3 5 2 6 3 0 5 1 1 4 1 3 0
|
||||
1 5 2 2 5 5 8 6 9 0 3 1 0 9 8 4 4 0 0 2 7 3 4 8 2 3 4 3 9 0 4 4 1 7 4 3 6 2 6 0 7 0 8 2 6 8 4 3 8 1 5 3 4 9 5 1 2 5 9 9 8 1 5 6 6 4 8 4 1 6 7 6 5 9 3 5 7 2 2 3 8 8 7 0 3 9 0 4 3 9 9 5 8 8 4 1 8 2 7 8
|
||||
2 1 4 2 8 1 4 6 2 7 1 6 2 6 2 9 4 3 4 3 6 1 1 5 2 2 1 2 8 0 1 8 4 2 5 3 1 3 8 8 6 3 7 4 0 6 9 9 1 0 4 6 9 7 6 8 1 9 4 9 7 4 9 2 9 9 3 7 9 7 2 8 7 8 5 0 1 5 6 3 1 2 2 5 3 9 9 8 7 3 6 1 7 4 5 3 3 1 8 6
|
||||
4 0 5 3 7 9 5 8 6 2 9 9 4 9 3 6 4 1 6 1 2 1 1 5 9 9 2 3 0 8 5 2 7 8 4 4 9 4 0 8 2 8 5 2 0 1 8 3 5 1 2 2 9 7 9 5 3 1 7 4 6 3 9 9 8 3 8 5 5 7 5 7 9 2 2 3 1 0 0 6 9 9 2 1 1 7 1 5 3 8 3 0 0 7 3 1 8 8 4 0
|
||||
9 0 8 5 2 7 4 4 1 6 5 0 1 5 4 9 2 2 7 1 3 2 4 0 2 5 0 2 5 0 4 1 4 5 0 7 3 8 6 2 5 7 5 3 1 4 0 4 5 2 1 7 9 0 2 1 9 1 8 0 7 5 1 2 6 5 9 2 3 5 6 0 7 4 5 3 1 6 0 7 0 4 4 7 0 4 8 2 4 1 6 1 1 7 5 5 1 9 6 9
|
||||
1 6 1 9 4 2 0 5 3 4 9 8 8 3 3 1 0 4 5 1 9 0 6 9 5 8 4 6 3 7 1 5 5 0 6 7 3 1 6 6 3 4 4 4 2 8 9 2 4 7 7 6 8 0 9 9 6 3 8 5 4 1 1 2 0 9 7 4 7 8 0 3 1 6 0 9 9 4 3 5 1 3 3 4 1 9 1 2 4 2 7 7 9 3 0 8 2 0 6 4
|
||||
7 5 2 4 5 2 0 9 8 8 3 5 3 5 8 0 1 7 3 8 3 8 9 4 8 4 2 8 2 2 2 9 8 5 3 7 3 1 5 7 4 8 5 3 2 1 6 8 6 4 8 9 9 5 4 8 5 1 9 9 8 6 9 6 7 1 4 9 0 7 8 7 6 0 9 3 1 8 5 2 2 1 1 3 5 6 3 0 4 3 4 7 5 7 4 0 3 6 9 6
|
||||
0 0 4 2 2 0 6 6 8 1 8 4 1 9 5 0 3 0 3 3 8 9 8 5 9 7 7 6 5 8 5 8 9 4 7 4 1 2 6 6 6 9 6 2 0 0 7 4 7 0 2 4 0 1 7 8 2 2 9 2 5 2 5 9 4 8 5 5 6 7 4 3 2 8 3 3 2 3 7 8 4 9 6 3 3 8 4 1 8 4 0 1 5 1 9 8 8 5 9 5
|
||||
6 3 5 0 8 5 4 2 7 3 5 8 6 9 6 4 2 2 1 8 9 8 8 8 4 5 0 8 7 2 6 3 2 9 7 7 7 4 9 6 9 2 2 8 0 2 7 4 7 2 6 6 3 0 2 3 1 6 6 2 0 6 3 1 4 3 5 4 5 7 9 3 2 4 4 3 0 6 1 1 9 3 5 0 1 1 4 3 0 2 5 2 2 3 2 9 0 4 8 9
|
||||
2 6 1 1 0 6 2 0 9 3 3 2 8 9 7 6 8 5 6 5 9 5 7 6 6 6 9 1 2 8 0 9 2 4 1 8 6 4 4 8 9 7 3 1 0 9 7 7 4 5 6 6 3 9 0 7 2 3 4 4 5 7 2 2 3 2 7 3 6 0 9 9 0 4 1 8 2 2 8 7 8 3 5 2 6 5 4 5 5 7 0 9 3 2 8 5 5 6 3 9
|
||||
5 7 5 0 1 9 3 0 2 8 5 3 0 3 7 5 6 7 1 2 4 8 5 1 2 0 2 1 1 1 8 9 4 9 7 7 0 2 8 4 2 0 8 6 9 7 7 0 5 6 4 2 1 6 0 1 2 6 3 8 8 4 1 0 9 4 0 2 7 7 9 1 6 6 6 6 6 8 7 3 9 9 7 8 5 3 7 3 0 2 0 5 5 4 0 0 5 9 3 3
|
||||
0 9 9 3 1 1 1 2 7 2 6 5 3 9 6 6 1 6 8 0 4 8 2 2 0 5 9 5 0 2 2 5 5 0 2 9 7 6 6 5 1 1 6 6 4 6 6 6 6 8 1 1 4 7 7 7 7 3 3 4 9 7 7 4 2 8 5 1 9 8 8 9 5 5 9 9 9 3 7 1 5 0 0 1 4 1 2 8 4 4 3 7 2 6 5 4 8 3 9 5
|
||||
3 8 8 5 3 6 5 3 5 7 7 2 6 3 7 1 1 5 1 7 4 3 6 7 3 4 7 3 1 9 8 1 3 9 7 3 9 7 6 2 2 4 7 2 2 0 4 8 4 5 3 7 7 9 1 2 4 9 7 9 9 6 3 6 8 7 9 7 3 5 7 9 5 8 8 2 5 4 2 7 4 6 5 7 5 9 4 5 8 2 9 5 4 8 0 5 7 5 0 4
|
||||
6 8 3 7 4 5 5 3 7 7 1 4 8 2 0 0 0 7 7 8 6 6 7 0 0 5 0 3 7 2 5 7 1 3 3 5 9 4 6 4 5 5 2 7 2 4 6 3 7 8 8 0 0 8 9 1 4 1 8 5 6 4 1 3 2 0 2 7 4 2 2 0 4 2 8 9 4 1 3 0 5 5 7 7 1 7 2 5 7 9 9 1 9 5 3 8 1 3 3 8
|
||||
4 2 7 8 3 5 2 8 0 1 7 8 0 0 7 5 4 9 6 8 7 9 6 9 0 7 1 7 3 7 2 5 7 8 9 9 6 1 9 8 3 3 4 2 6 5 2 7 5 6 5 3 5 5 3 1 6 6 8 4 8 7 3 3 4 6 0 4 8 5 1 7 8 7 7 6 3 2 9 0 8 7 4 2 9 6 7 7 2 3 2 4 8 7 4 2 5 7 4 0
|
||||
9 6 9 8 9 0 7 7 0 5 3 1 6 7 4 4 2 4 0 1 0 2 7 1 9 4 5 6 0 2 7 8 9 8 2 6 9 0 6 6 2 8 1 3 1 4 3 8 2 0 8 3 8 9 9 3 0 0 1 2 6 4 5 8 0 0 6 5 4 5 9 8 6 9 8 2 0 7 5 6 3 0 0 9 8 5 3 3 0 8 2 9 8 2 3 3 3 5 2 3
|
||||
0 6 9 9 0 4 2 2 5 4 1 4 1 1 8 0 1 2 6 8 2 1 3 7 4 7 5 2 5 4 6 8 4 8 9 3 1 4 7 8 3 1 8 8 6 7 0 3 1 5 5 9 1 7 3 2 5 7 0 8 2 4 0 8 5 5 0 8 1 8 6 9 5 1 5 4 1 9 5 4 2 0 7 1 7 4 8 2 6 9 6 8 3 2 1 8 6 4 5 1
|
||||
0 5 4 0 6 2 8 3 0 0 1 5 6 4 1 0 3 7 2 1 0 8 2 6 8 6 7 0 2 0 5 1 6 7 9 6 9 6 9 5 1 7 1 0 1 8 6 6 9 5 8 1 8 2 9 1 7 3 7 2 1 8 2 7 0 8 3 7 4 6 1 6 5 2 0 3 0 9 6 0 8 8 6 2 0 4 5 2 8 6 9 6 8 2 3 7 5 3 2 2
|
||||
6 0 2 3 6 4 9 3 3 0 7 8 2 5 8 2 2 4 2 1 4 3 2 0 5 8 0 1 9 8 2 5 6 5 4 9 3 9 5 1 7 5 7 2 3 8 6 0 8 0 0 0 8 5 3 6 4 0 8 5 4 9 4 2 9 4 3 3 2 4 0 5 4 2 4 4 9 0 8 4 3 9 4 6 9 6 2 6 9 5 1 4 6 5 0 8 3 9 4 3
|
||||
0 1 2 8 0 3 3 8 7 1 1 0 9 0 1 1 7 1 1 5 1 5 0 3 5 1 8 2 4 0 6 5 0 9 7 0 1 5 6 1 0 3 2 9 0 3 0 0 1 9 5 6 0 2 0 8 2 4 1 5 0 1 6 8 3 8 4 8 4 1 9 7 4 6 4 3 2 7 9 9 6 1 5 6 8 2 8 9 0 7 6 1 2 4 9 4 7 4 6 5
|
||||
6 8 0 3 8 0 6 6 5 1 1 6 7 6 2 1 7 0 7 0 8 9 5 8 6 3 4 0 9 5 2 9 8 5 4 7 5 1 3 1 3 5 0 8 1 9 1 2 8 4 8 7 2 3 5 8 9 3 7 8 5 3 5 7 1 3 9 6 0 1 1 1 6 4 2 6 1 3 4 5 0 6 5 2 5 7 3 0 5 9 4 5 4 3 1 8 9 5 8 0
|
||||
4 6 7 8 9 3 8 7 2 2 9 1 7 4 9 4 8 8 8 5 6 6 4 2 3 3 8 6 7 0 8 2 4 6 2 9 2 6 9 1 9 8 7 6 5 3 1 4 9 9 5 5 2 3 5 4 0 7 4 3 8 6 7 1 6 3 7 0 4 7 7 1 8 4 3 9 0 7 2 8 2 0 2 7 0 2 9 8 3 4 8 9 1 6 6 4 0 1 2 5
|
||||
7 9 5 9 3 8 2 1 4 0 4 0 3 8 0 0 5 2 2 9 2 1 9 4 3 7 1 8 0 5 4 8 8 9 8 6 3 9 3 7 2 0 0 9 7 2 7 6 2 6 9 7 0 8 6 9 7 2 9 1 6 3 4 3 5 6 7 6 7 9 5 9 4 1 3 0 1 0 2 9 0 3 4 1 7 8 2 4 8 2 4 4 3 5 6 7 8 7 2 6
|
||||
3 2 4 1 7 1 5 4 0 0 6 8 1 1 9 0 9 0 7 5 3 4 5 2 0 6 2 6 0 8 8 4 7 0 2 4 1 0 7 5 9 9 1 4 3 8 5 2 6 0 3 5 0 6 1 7 9 1 3 5 3 8 1 9 0 4 7 8 1 8 0 4 7 8 1 5 8 2 9 9 6 0 2 9 6 2 5 1 5 8 1 9 9 6 6 7 3 8 2 7
|
||||
0 5 9 2 3 4 1 0 2 1 1 4 1 0 4 3 7 3 2 8 2 5 5 8 1 6 7 0 0 8 5 5 6 6 3 4 5 8 6 3 5 8 5 8 6 1 4 7 4 0 9 8 4 3 8 6 7 0 6 1 1 4 7 9 1 9 2 4 9 7 7 9 2 9 7 4 9 1 6 7 4 9 1 7 1 2 3 0 2 0 9 3 9 1 1 7 5 1 4 0
|
||||
2 2 8 7 3 4 2 9 8 7 6 8 2 3 3 2 0 0 8 4 8 9 2 1 9 9 4 8 9 1 6 9 0 4 5 9 1 3 7 6 1 1 7 0 2 0 3 9 0 8 6 8 0 6 3 7 4 6 5 6 2 7 4 6 1 1 6 5 1 8 7 2 8 9 2 0 7 1 0 2 5 4 3 1 6 0 2 4 6 8 1 5 4 5 8 1 2 4 9 3
|
||||
6 9 9 4 1 0 6 1 8 5 9 5 7 5 9 5 7 3 2 5 7 1 4 5 6 1 6 8 1 8 2 5 5 6 6 4 7 8 3 0 8 9 6 7 8 3 3 3 8 2 8 1 5 1 1 3 8 6 6 4 4 4 4 9 6 8 2 5 0 5 7 2 8 4 1 0 4 2 8 4 4 3 1 9 6 9 0 5 5 5 0 6 7 2 4 2 8 0 7 4
|
||||
6 6 4 5 7 0 0 9 6 8 0 0 6 6 0 9 8 1 3 1 2 0 0 5 7 0 3 1 5 4 7 1 2 3 2 1 1 2 2 1 4 5 4 1 7 4 1 6 1 4 3 7 8 2 8 9 1 1 0 8 4 7 1 5 0 1 9 0 7 4 7 5 5 0 2 3 7 5 1 7 6 4 0 7 4 2 3 4 3 3 7 8 1 4 8 4 5 2 9 8
|
||||
0 0 9 1 0 5 5 6 0 2 5 3 4 6 9 4 3 7 1 0 3 5 0 0 7 9 1 8 3 9 0 4 1 5 1 1 3 4 8 7 1 4 2 8 3 9 3 5 9 7 3 3 0 8 7 8 3 3 5 9 9 3 5 0 6 8 5 8 4 3 5 7 5 3 3 5 7 4 9 6 7 5 1 1 4 2 1 2 2 4 1 5 8 2 9 4 8 6 8 5
|
||||
0 1 2 3 7 3 5 1 7 7 6 9 5 6 3 6 4 6 2 3 6 5 8 2 6 7 8 7 1 6 0 8 6 5 7 0 3 4 4 4 6 2 1 4 4 1 0 8 2 8 4 8 9 5 2 5 1 2 9 2 2 2 1 4 2 6 3 7 7 4 9 4 6 8 5 1 8 1 8 1 6 3 6 8 8 4 3 0 6 2 0 6 1 7 9 5 2 7 7 9
|
||||
5 4 4 3 3 0 2 7 2 5 7 1 6 2 4 3 0 4 1 3 7 4 5 7 0 9 8 6 8 2 0 0 8 4 7 9 2 3 5 1 8 9 4 0 7 8 0 2 6 5 4 4 2 3 3 3 7 3 2 2 2 5 0 0 3 4 0 3 3 4 9 4 1 4 8 7 6 8 0 1 0 4 0 5 9 3 5 2 0 0 7 9 4 0 6 5 8 1 7 8
|
||||
8 5 7 3 4 0 8 5 1 6 2 1 4 3 6 6 4 3 6 4 7 5 8 7 3 1 1 1 8 1 8 2 1 9 7 1 7 7 6 1 6 4 9 7 8 8 5 7 1 2 1 7 2 9 3 5 6 5 0 3 9 7 8 8 8 0 2 7 8 1 0 7 6 0 1 7 8 1 3 8 2 4 9 7 0 4 5 8 6 0 0 0 8 6 5 1 9 0 2 2
|
||||
9 9 7 7 7 6 8 3 3 5 9 9 4 4 8 5 6 0 3 6 9 1 3 4 8 7 1 6 8 7 6 0 4 8 4 6 0 9 1 2 2 0 6 1 1 0 9 5 4 2 5 0 7 1 1 1 8 5 0 3 6 3 9 5 6 0 6 6 5 4 7 5 0 0 4 0 3 6 4 0 6 6 2 2 4 8 1 7 8 7 1 7 1 0 2 8 0 2 9 0
|
||||
2 4 5 1 1 6 9 4 3 6 5 0 4 7 7 0 4 3 4 6 0 5 6 1 0 0 0 3 0 9 2 3 0 2 6 4 8 2 1 4 0 1 3 2 3 1 8 6 0 8 3 9 9 9 7 9 0 5 7 3 2 0 0 2 9 7 1 7 6 8 9 5 4 4 0 1 8 1 2 7 1 9 1 2 6 4 1 5 5 5 5 6 3 1 8 1 3 0 9 2
|
||||
4 4 5 4 1 4 4 1 7 1 6 6 0 4 8 1 7 6 8 6 6 2 0 6 0 4 5 2 6 8 2 4 1 6 2 8 9 6 6 8 2 1 6 3 3 5 3 9 4 4 7 6 6 7 0 4 4 7 7 9 4 2 9 1 2 2 8 6 2 7 9 9 9 7 3 7 1 8 3 7 7 6 3 9 7 5 5 8 6 2 2 0 3 1 2 5 0 9 1 4
|
||||
0 6 1 0 9 4 6 0 7 0 9 7 4 0 8 3 0 5 8 4 7 9 3 0 6 0 1 4 3 7 8 9 3 9 7 8 0 1 2 9 2 3 3 1 9 2 2 6 8 4 2 3 4 9 8 7 1 5 5 0 2 1 0 2 1 0 5 8 0 4 3 3 2 6 3 4 3 8 1 4 1 7 4 6 7 2 9 3 7 5 2 0 7 6 4 6 1 4 6 5
|
||||
0 0 9 1 0 6 3 4 0 7 3 9 0 6 4 0 3 1 1 3 1 0 3 4 4 0 8 6 8 5 5 6 7 9 1 7 6 1 9 3 6 6 8 5 9 3 0 1 4 2 3 5 5 6 1 9 2 0 3 8 5 5 7 0 0 8 2 5 1 3 9 1 9 5 4 9 4 6 8 4 9 6 5 9 2 3 9 3 8 1 9 7 8 5 5 8 4 4 8 0
|
||||
9 3 0 8 7 3 4 0 3 9 9 1 4 6 4 8 0 8 0 8 0 1 9 2 8 0 9 8 7 1 7 0 7 9 0 2 8 3 0 9 9 0 2 3 9 8 6 0 1 9 7 2 5 5 8 6 7 8 5 2 6 8 0 7 8 1 6 1 9 5 7 7 9 0 9 1 8 5 2 9 1 6 6 9 7 5 3 5 1 5 8 5 1 6 7 5 8 4 2 6
|
||||
8 2 6 9 9 5 8 8 4 6 3 8 9 4 9 9 2 8 6 5 2 8 0 0 2 8 9 2 5 2 9 1 8 9 3 8 8 4 0 5 2 0 5 8 7 1 7 5 4 0 0 6 2 3 5 7 2 3 3 8 9 3 9 9 9 0 2 3 7 9 8 2 9 8 7 2 3 2 5 9 0 7 6 1 7 6 5 0 6 5 3 4 6 0 2 3 2 6 1 0
|
||||
6 4 2 6 7 0 5 6 0 2 8 7 9 9 5 7 4 7 5 4 1 5 5 4 6 7 4 7 0 9 4 6 6 5 7 6 8 7 9 7 8 0 5 0 1 2 7 0 5 0 6 3 9 4 2 4 4 5 4 4 6 4 1 0 8 5 5 3 0 3 6 3 2 2 0 1 8 6 8 0 2 2 4 9 6 7 8 9 2 0 8 8 0 7 4 0 8 5 1 2
|
||||
8 6 1 0 5 0 1 9 1 0 1 2 4 2 5 6 3 9 1 6 8 6 7 1 0 2 2 1 9 2 1 8 8 0 8 0 3 8 3 4 2 9 1 9 1 8 5 5 4 0 1 9 9 1 6 2 3 0 6 9 7 4 7 5 7 9 3 6 3 1 9 0 1 4 8 5 2 5 5 7 7 6 3 8 0 0 7 8 8 4 7 0 7 0 8 9 2 2 2 4
|
||||
2 4 9 2 8 7 9 8 0 3 0 9 0 5 3 6 7 2 0 4 6 0 0 6 4 9 3 7 5 8 7 0 5 7 8 3 4 8 3 4 7 4 8 9 8 2 8 3 0 4 6 9 1 8 0 8 3 2 1 0 7 9 3 6 2 0 3 4 4 3 4 3 4 0 9 1 0 9 2 7 5 3 1 3 6 5 1 9 6 5 6 9 9 7 5 9 5 6 5 1
|
||||
0 7 8 9 3 3 3 8 0 5 4 0 3 1 8 6 0 8 6 0 7 3 6 6 5 8 4 7 9 7 8 5 8 3 6 5 1 2 0 4 1 4 5 0 6 6 9 6 9 3 5 1 5 3 0 5 7 7 9 4 0 0 7 9 2 3 7 7 3 4 8 3 0 5 0 8 9 3 8 2 7 6 3 0 8 2 2 5 1 9 7 6 4 6 7 3 2 7 9 2
|
||||
8 5 9 5 6 7 4 8 6 4 3 9 7 3 8 6 1 3 0 8 8 3 0 6 9 5 5 1 3 5 0 8 9 2 0 0 7 2 7 7 0 6 2 8 3 6 9 6 4 8 0 9 8 8 2 1 9 4 1 4 0 8 0 7 0 7 5 3 9 2 9 8 6 5 2 0 3 9 8 6 2 0 0 8 9 5 2 4 9 0 9 3 1 8 1 3 2 6 9 5
|
||||
9 7 4 4 4 1 1 5 7 8 1 4 7 1 0 3 7 2 8 7 9 2 9 3 7 7 0 7 2 6 6 9 1 9 3 6 9 9 7 0 4 4 2 7 2 2 4 8 9 7 4 1 6 7 6 3 8 7 9 6 6 6 3 7 5 4 1 9 6 5 0 5 1 2 1 7 9 9 2 1 4 0 5 3 6 2 3 5 2 9 5 0 9 1 3 7 5 3 5 1
|
||||
6 6 6 3 1 5 2 0 3 1 8 1 6 3 2 5 4 7 7 3 9 8 8 5 3 1 9 4 4 1 7 2 1 8 5 4 6 6 3 8 4 4 7 5 8 8 7 3 9 8 3 3 5 4 1 0 5 4 3 5 5 5 6 6 5 0 3 8 4 1 8 2 2 6 0 8 6 6 7 5 0 8 4 0 5 6 6 4 7 6 8 1 9 6 3 5 4 7 1 5
|
||||
6 0 5 7 0 0 2 4 2 0 8 6 5 2 2 6 8 6 7 7 8 7 8 9 7 0 2 5 9 2 4 8 2 6 9 2 2 3 1 9 8 4 2 8 1 1 5 0 9 1 1 7 0 1 4 3 1 7 5 6 2 6 7 2 6 2 9 5 0 3 7 0 1 8 4 2 5 9 1 7 9 8 7 3 3 4 8 5 4 6 5 1 3 3 8 3 9 0 3 5
|
||||
8 8 7 9 6 9 1 1 3 9 9 1 8 2 5 1 1 3 4 5 5 6 4 5 6 5 3 3 1 9 2 5 6 3 6 4 6 0 4 7 8 2 2 7 4 7 1 0 4 0 5 2 3 1 7 5 5 7 6 6 9 0 0 6 3 8 3 5 3 7 9 9 7 6 9 9 8 7 2 4 4 1 5 7 4 7 4 0 8 5 5 6 6 7 6 8 5 2 9 6
|
||||
0 5 2 1 9 0 2 4 1 9 2 0 7 0 9 9 6 7 1 2 5 1 6 2 5 0 5 6 3 3 6 4 6 1 5 3 6 9 2 8 2 8 4 7 9 9 5 0 2 1 4 3 0 5 4 6 6 6 6 6 9 5 2 9 4 6 3 7 4 6 2 9 8 4 7 6 5 0 8 8 6 0 3 9 9 7 4 7 6 8 0 1 3 5 3 8 6 6 6 5
|
||||
6 0 5 1 5 9 0 2 0 7 3 5 6 9 9 0 0 3 0 2 0 6 0 3 0 4 5 2 4 6 7 5 1 9 0 6 2 1 1 7 5 0 6 2 7 0 5 9 9 0 6 7 4 5 9 3 3 9 8 6 0 1 5 3 1 4 7 8 8 0 9 1 8 9 2 4 3 2 2 9 2 5 2 2 1 3 5 1 5 0 8 4 3 2 8 1 1 7 0 1
|
||||
0 4 3 2 7 1 0 1 9 2 2 1 6 8 6 8 6 1 7 2 3 0 3 2 8 4 8 5 6 3 7 6 9 3 9 8 8 6 8 7 1 7 8 7 1 2 3 9 2 8 6 0 5 4 6 6 3 3 1 2 7 4 7 7 2 4 7 4 5 3 7 9 1 3 3 2 5 9 1 1 8 6 8 2 0 1 8 9 6 7 0 4 3 3 9 4 4 3 3 9
|
||||
7 8 4 9 3 4 9 5 1 9 6 3 8 7 3 7 6 9 2 3 1 4 0 5 1 2 2 7 0 9 3 0 7 2 7 7 3 4 6 8 5 2 1 7 5 5 0 8 9 8 8 6 5 8 6 4 0 6 0 2 7 1 6 7 5 3 8 8 8 1 7 4 1 9 8 7 2 9 9 8 2 8 2 4 0 0 3 4 0 2 5 6 5 5 4 7 4 9 1 1
|
||||
0 9 8 9 7 1 1 6 0 5 7 0 7 4 0 8 9 0 1 0 6 5 7 2 9 8 5 8 3 5 3 3 8 4 2 7 4 6 2 8 4 6 3 5 2 3 7 2 8 9 8 2 3 2 6 3 8 4 3 6 5 4 5 1 4 6 2 3 9 1 8 9 5 5 6 6 9 4 8 5 1 2 7 9 9 4 3 6 6 6 1 5 2 8 7 3 5 9 8 2
|
||||
9 9 1 3 8 0 6 8 0 8 6 6 2 3 5 4 1 8 2 6 9 7 1 0 6 8 8 6 4 7 3 1 0 0 9 5 2 5 1 6 1 8 9 1 3 2 3 4 6 2 0 0 2 5 0 5 8 6 8 9 1 7 9 1 6 3 3 0 8 6 2 1 7 6 0 3 6 0 9 0 1 6 4 2 5 1 7 1 2 3 3 1 5 3 0 0 4 5 0 5
|
||||
4 4 6 0 2 7 1 3 5 0 8 6 4 3 7 1 7 4 4 3 1 0 1 8 8 4 3 0 7 1 8 6 1 4 4 8 5 2 9 9 0 3 0 8 2 0 4 3 7 2 7 4 5 7 7 5 0 1 5 8 4 5 3 4 1 2 9 9 0 0 7 4 9 8 9 2 6 9 9 0 3 6 1 9 2 5 1 2 5 9 5 0 4 6 4 4 6 1 8 6
|
||||
6 9 8 5 1 7 8 8 1 9 4 7 0 6 4 7 2 4 5 7 1 8 1 4 9 2 3 3 5 4 8 8 2 2 9 5 6 1 5 2 9 7 8 5 5 0 4 1 9 8 5 5 5 7 7 6 9 1 3 9 5 0 8 0 7 7 6 2 3 7 2 0 3 6 9 8 6 2 5 5 3 0 6 5 0 7 4 4 3 4 4 3 2 0 4 0 3 8 8 5
|
||||
6 8 0 9 9 2 9 6 3 9 2 1 7 6 8 6 2 5 7 4 9 3 3 8 3 8 0 8 4 8 3 2 0 2 2 1 6 6 3 2 3 0 6 4 0 8 3 8 4 9 7 9 9 2 0 7 8 4 4 0 1 8 4 2 9 2 8 4 2 8 1 0 3 5 2 3 6 3 9 6 9 6 1 3 2 7 0 7 9 2 8 1 8 2 4 8 2 2 9 8
|
||||
7 2 8 2 8 4 3 2 4 1 1 4 4 1 7 0 4 5 9 0 7 0 1 2 3 3 9 2 1 3 5 7 6 0 2 4 3 3 5 1 8 7 6 3 3 7 6 5 1 3 4 5 0 0 6 4 2 0 7 9 1 5 4 7 2 6 5 4 0 2 6 1 6 7 2 6 4 7 2 5 4 9 1 0 8 9 5 7 6 4 4 2 0 3 3 5 9 2 3 0
|
||||
7 7 3 2 7 5 1 5 9 2 9 7 7 7 6 5 6 3 1 3 4 1 8 3 2 5 7 6 7 3 7 7 9 5 3 6 3 5 6 0 5 1 3 1 9 9 5 2 2 3 4 7 6 7 8 9 2 5 1 0 7 0 6 9 2 5 3 6 7 0 6 7 7 2 3 2 9 3 0 1 2 8 6 8 5 7 5 6 9 9 6 4 2 2 2 3 4 8 5 3
|
||||
4 0 5 1 9 8 9 6 8 9 8 8 0 1 2 0 8 7 7 5 5 6 8 8 4 9 9 2 7 8 0 3 6 8 2 6 8 1 4 8 7 5 3 6 2 0 7 2 7 8 1 2 8 3 8 4 3 9 8 7 5 6 7 9 7 7 2 2 1 6 2 2 6 0 0 6 9 2 1 2 7 3 6 3 6 5 5 5 8 0 0 2 6 6 7 9 6 4 4 4
|
||||
6 3 5 0 0 4 2 2 1 1 2 2 7 9 5 6 9 6 6 5 6 5 3 5 0 0 0 1 2 4 9 0 5 3 2 8 8 1 7 9 4 4 9 1 5 5 5 6 1 0 0 1 2 6 7 4 5 5 6 5 3 4 6 6 3 6 1 9 2 8 5 4 2 8 9 0 6 0 4 2 7 1 6 7 5 1 4 4 3 0 2 3 3 3 2 5 4 0 7 2
|
||||
2 4 1 0 3 2 0 5 4 6 8 3 5 8 2 1 1 5 4 5 4 9 4 6 4 3 6 3 6 1 7 9 3 0 4 6 1 2 7 9 8 5 6 8 0 6 7 8 0 5 9 9 0 3 6 3 6 3 3 2 4 8 0 2 3 9 1 9 7 0 1 7 1 5 5 1 9 8 4 8 3 8 5 9 6 2 8 5 3 0 1 8 4 3 5 7 8 7 1 3
|
||||
1 0 4 7 4 2 1 0 9 8 5 7 6 3 7 5 9 5 1 2 8 5 7 5 6 9 4 1 6 6 7 8 3 6 3 2 3 7 4 7 2 2 8 2 5 1 3 1 5 2 9 1 1 7 3 5 8 0 0 1 6 7 4 3 8 6 0 3 0 6 3 5 5 8 8 9 1 3 4 0 7 9 2 6 0 1 6 2 6 2 6 9 2 6 2 0 0 9 4 8
|
||||
9 8 5 2 5 4 4 6 3 8 6 9 1 5 7 2 1 6 5 2 8 0 5 1 5 8 2 6 4 7 9 9 5 2 0 1 6 0 9 3 9 8 6 7 5 9 1 2 3 6 7 7 7 4 7 3 4 5 9 7 4 6 3 3 4 1 3 2 1 3 1 1 3 9 1 7 0 0 1 4 0 5 6 0 6 6 1 0 4 0 9 3 1 7 9 3 6 8 1 0
|
||||
8 1 1 2 4 2 7 2 4 9 0 4 4 6 2 4 8 8 3 1 4 3 8 3 1 3 9 7 5 5 4 1 7 3 8 9 4 1 5 9 4 5 1 8 8 1 9 1 0 8 4 8 7 4 9 4 5 9 7 0 2 1 3 0 4 3 3 7 1 9 0 2 6 7 6 0 3 5 5 2 9 0 2 5 4 6 2 1 3 1 1 3 4 7 2 4 1 0 5 5
|
||||
5 4 0 7 8 5 1 5 6 0 8 4 1 3 6 1 7 0 3 8 0 2 9 0 2 7 0 6 5 3 4 0 5 3 9 6 4 2 8 7 4 7 8 7 4 2 8 2 5 8 0 6 3 2 7 0 4 5 2 6 5 5 8 8 3 3 4 4 3 9 3 5 3 2 3 5 3 8 1 7 2 2 6 0 9 4 6 7 7 0 2 7 9 5 9 7 6 7 8 2
|
||||
6 3 6 7 1 4 8 8 5 5 4 3 5 1 7 4 1 9 1 8 4 0 2 8 1 5 9 1 8 0 6 7 5 1 2 2 3 6 3 0 2 2 6 7 0 9 4 1 9 2 2 6 0 5 1 1 9 1 8 5 3 9 8 6 3 1 4 3 7 0 3 8 1 2 9 7 7 9 2 1 8 2 6 4 0 1 2 6 5 0 6 8 0 1 7 5 6 2 0 0
|
||||
2 3 7 6 8 8 1 7 3 1 7 1 4 4 2 6 5 1 6 6 7 2 3 3 0 3 9 0 1 7 8 8 4 5 0 4 7 9 6 0 0 5 6 3 1 3 8 8 2 7 0 4 2 0 8 9 9 8 9 1 4 9 1 2 1 5 9 0 3 9 2 9 9 0 9 9 9 3 7 7 1 0 1 1 7 1 5 2 5 3 2 1 8 4 3 4 1 0 0 2
|
||||
6 2 1 6 8 4 9 7 9 2 2 3 4 2 2 6 8 9 5 0 3 4 0 9 9 1 8 0 7 5 2 7 2 7 8 1 9 6 1 4 6 3 6 6 1 8 1 8 6 0 1 6 7 8 8 6 6 1 5 0 1 6 7 2 7 2 1 0 7 6 0 4 0 6 7 5 5 5 4 7 1 3 7 8 8 0 3 1 1 0 4 2 1 3 8 2 9 7 4 2
|
||||
8 0 2 7 8 8 5 7 0 7 0 3 1 5 4 7 1 5 7 5 3 5 8 3 8 7 4 6 7 4 0 0 5 4 1 9 7 8 0 1 6 2 0 0 2 1 3 7 4 1 7 5 3 7 4 1 0 8 1 8 2 6 4 5 0 6 3 3 1 0 0 5 7 7 6 6 5 9 6 3 8 8 9 7 7 8 3 9 7 2 0 5 4 1 7 7 3 1 8 0
|
||||
9 5 6 9 4 3 6 0 5 0 9 1 4 3 7 1 4 9 6 2 7 7 4 9 3 3 1 3 4 8 7 7 6 0 8 8 0 6 8 4 7 8 5 9 9 1 3 0 7 5 0 0 4 7 9 6 1 7 3 8 9 8 6 5 4 4 7 2 5 8 8 3 6 5 4 9 1 2 6 2 6 9 1 9 8 7 3 2 6 0 9 8 2 9 9 7 5 8 9 7
|
||||
8 0 9 3 5 3 5 1 1 5 0 2 2 0 2 0 4 4 9 5 6 0 1 5 2 0 1 1 1 6 7 5 0 0 0 4 8 5 6 9 6 3 0 2 0 7 5 8 1 3 3 8 4 1 7 3 5 9 6 5 0 1 6 2 9 9 4 4 5 9 8 9 3 7 7 9 8 1 7 8 7 8 7 7 2 8 6 6 9 3 1 3 7 2 0 5 6 3 9 7
|
||||
8 8 5 7 5 1 5 6 9 3 9 9 7 2 9 7 3 8 7 9 7 1 6 0 3 7 4 8 2 5 3 8 4 9 6 2 3 1 5 8 9 9 4 2 4 0 9 0 9 3 4 4 2 8 2 4 8 0 7 4 8 8 3 6 1 2 0 1 4 3 8 7 3 4 9 8 2 1 3 3 3 0 4 9 0 1 6 9 8 9 2 7 4 1 3 9 3 1 6 4
|
||||
1 0 7 2 1 0 0 4 6 0 2 0 5 8 4 8 6 5 8 7 2 7 1 8 5 5 4 3 9 7 6 4 1 7 4 1 8 7 6 4 5 1 8 5 6 7 9 9 0 3 0 4 3 2 7 3 2 8 3 3 4 8 8 3 4 9 0 8 8 4 1 1 2 6 3 9 5 9 2 3 0 3 7 2 9 4 9 0 7 9 0 9 1 3 2 7 3 8 6 2
|
||||
1 7 6 1 5 1 7 1 3 0 6 0 8 0 7 7 2 7 7 8 1 6 3 1 7 0 0 4 9 7 8 7 6 3 0 9 4 4 7 9 0 1 7 5 3 2 6 3 1 9 2 7 2 2 3 5 9 7 7 9 8 3 6 9 4 6 9 0 6 4 2 9 9 7 6 1 4 7 8 8 5 2 7 1 7 8 7 3 1 8 5 7 5 3 6 6 4 1 8 6
|
||||
2 9 4 7 1 2 1 3 1 6 0 1 5 1 1 4 5 7 2 9 8 0 9 0 0 7 2 4 1 7 6 1 0 4 8 3 1 8 2 6 8 3 2 9 8 4 2 9 3 5 9 2 4 3 6 3 6 5 1 9 3 6 7 3 9 5 5 2 0 5 2 1 6 7 9 9 2 0 0 3 1 3 1 5 6 6 4 2 7 4 8 5 2 8 6 7 9 3 1 5
|
||||
7 3 6 4 3 3 1 6 1 9 4 1 5 8 3 7 7 4 9 5 3 1 1 8 7 8 5 7 5 0 0 7 0 4 1 5 5 8 3 9 3 7 7 1 9 7 5 8 6 2 9 1 0 2 7 8 7 0 9 7 4 0 3 8 9 0 8 2 2 3 2 0 8 7 8 8 3 5 8 0 3 4 5 3 6 7 8 3 5 4 8 2 4 1 9 8 9 8 7 9
|
||||
2 3 6 2 1 1 8 4 7 3 0 1 0 4 3 0 3 1 7 3 1 8 5 7 5 3 4 7 8 5 1 0 3 1 3 0 6 4 5 9 7 3 0 4 3 6 5 1 7 3 3 6 9 7 8 0 8 6 1 8 1 1 2 8 5 1 5 1 1 1 2 8 9 2 6 8 9 8 3 8 7 6 2 8 9 5 5 9 5 3 1 8 9 4 4 9 1 0 8 3
|
||||
5 1 9 3 7 6 9 4 0 4 1 9 7 2 6 6 4 7 9 7 7 8 4 8 2 4 6 9 3 9 2 9 2 8 8 6 6 1 6 0 6 2 8 3 8 7 2 4 7 2 0 6 6 2 1 6 5 2 0 0 9 8 3 9 6 3 4 4 4 5 8 1 9 2 3 2 8 1 5 7 8 0 9 7 4 2 9 4 0 6 3 3 0 3 3 7 2 5 4 8
|
||||
6 2 5 7 2 0 6 1 0 2 4 5 2 8 3 3 5 7 1 5 1 7 8 9 2 0 0 3 3 9 1 7 8 9 3 9 2 1 8 5 1 8 2 2 5 5 3 0 9 5 5 0 4 1 9 8 1 5 5 9 2 1 5 7 3 4 9 0 3 2 8 4 0 5 5 4 9 8 6 6 8 7 0 1 0 5 0 9 9 3 5 6 6 8 5 5 5 0 0 9
|
||||
6 8 3 2 1 1 3 9 4 9 3 9 0 6 1 2 3 2 5 9 3 6 3 2 0 1 1 1 8 9 4 2 2 2 7 6 0 4 5 2 8 1 8 8 1 4 3 3 0 9 1 4 8 3 6 6 1 6 7 1 7 0 4 9 1 9 2 2 4 5 0 7 5 2 4 5 9 7 5 1 6 9 0 0 5 8 1 4 6 1 5 1 9 2 0 9 2 6 1 2
|
||||
3 3 4 5 5 7 6 4 7 3 1 6 5 4 5 6 8 0 9 5 7 9 6 2 4 8 2 0 1 9 0 7 9 6 4 3 7 2 5 2 4 0 0 1 0 9 5 1 8 9 1 8 3 5 8 9 3 6 2 0 3 0 2 8 4 3 3 5 5 0 3 3 2 1 0 6 2 8 2 7 1 2 2 6 4 4 3 2 4 1 2 8 9 7 0 9 1 4 6 9
|
||||
6 3 8 6 6 0 3 6 0 6 7 7 6 3 8 9 7 9 4 8 2 2 8 3 2 4 0 1 1 7 5 4 2 7 7 6 9 2 0 2 4 4 8 2 6 5 2 2 9 3 5 8 6 9 2 9 7 0 7 9 6 4 8 6 5 5 3 4 9 0 9 0 8 7 5 7 8 8 5 1 2 0 3 7 9 4 8 9 6 6 2 8 2 4 7 8 7 1 3 4
|
||||
9 9 1 4 2 6 0 9 1 0 0 5 2 9 1 7 6 9 0 6 6 4 9 3 7 3 7 5 3 5 2 1 6 7 4 4 5 4 6 5 8 2 3 8 4 3 8 5 2 7 7 9 2 3 8 2 5 2 5 7 6 8 2 1 3 4 3 5 5 3 5 7 5 9 6 4 8 8 3 8 5 3 8 8 7 9 0 2 3 5 2 4 8 8 2 9 8 0 1 9
|
||||
3
04-MatrixAddition (pthread)/matrices/vector1
Normal file
3
04-MatrixAddition (pthread)/matrices/vector1
Normal file
@@ -0,0 +1,3 @@
|
||||
2 1
|
||||
1
|
||||
2
|
||||
3
04-MatrixAddition (pthread)/matrices/vector2
Normal file
3
04-MatrixAddition (pthread)/matrices/vector2
Normal file
@@ -0,0 +1,3 @@
|
||||
2 1
|
||||
5
|
||||
8
|
||||
100
04-MatrixAddition (pthread)/matsaddth.c
Normal file
100
04-MatrixAddition (pthread)/matsaddth.c
Normal file
@@ -0,0 +1,100 @@
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Value depend on System core
|
||||
#define CORE 4
|
||||
|
||||
typedef struct matrix
|
||||
{
|
||||
int r;
|
||||
int c;
|
||||
int *v;
|
||||
} matrix;
|
||||
|
||||
matrix A, B, R;
|
||||
|
||||
void read_matrix(matrix *m, const char *filename)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
fscanf(f, "%d %d", &(m->r), &(m->c));
|
||||
m->v = malloc(sizeof(int) * m->r * m->c);
|
||||
for (int i = 0; i < m->r; i++)
|
||||
{
|
||||
for (int j = 0; j < m->c; j++)
|
||||
{
|
||||
int value;
|
||||
fscanf(f, "%d", &value);
|
||||
m->v[i * m->c + j] = value;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void print_matrix(const matrix *m)
|
||||
{
|
||||
for (int i = 0; i < m->r; i++)
|
||||
{
|
||||
for (int j = 0; j < m->c; j++)
|
||||
{
|
||||
printf("%d ", m->v[i * m->c + j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct thargs
|
||||
{
|
||||
int start;
|
||||
int end;
|
||||
} thargs;
|
||||
|
||||
// Addition of a Matrix
|
||||
void *addition(void *arg)
|
||||
{
|
||||
thargs *x = (thargs *)arg;
|
||||
// Each thread computes 1/4th of matrix addition
|
||||
for (int i = x->start; i < x->end; i++)
|
||||
{
|
||||
R.v[i] = A.v[i] + B.v[i];
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
read_matrix(&A, argv[1]);
|
||||
read_matrix(&B, argv[2]);
|
||||
if (A.r == B.r && A.c == B.c)
|
||||
{
|
||||
R.r = A.r;
|
||||
R.c = A.c;
|
||||
R.v = malloc(sizeof(int) * R.r * R.c);
|
||||
}
|
||||
printf("Matrix A\n");
|
||||
print_matrix(&A);
|
||||
printf("\nMatrix B\n");
|
||||
print_matrix(&B);
|
||||
|
||||
int comps_per_thread = (CORE * 2) / (A.r * A.c);
|
||||
pthread_t thread[CORE * 2];
|
||||
thargs args[CORE * 2];
|
||||
for (int i = 0; i < CORE * 2; i++)
|
||||
{
|
||||
thargs args[i] = {i * comps_per_thread, ((i + 1) * comps_per_thread)};
|
||||
pthread_create(&thread[i], NULL, &addition, &args[i]);
|
||||
}
|
||||
|
||||
// Waiting for join threads after compute
|
||||
for (i = 0; i < CORE * 2; i++)
|
||||
{
|
||||
|
||||
pthread_join(thread[i], NULL);
|
||||
}
|
||||
|
||||
// Display Addition of mat_A and mat_B
|
||||
printf("\nSum of Matrix A and B:\n");
|
||||
print_matrix(&R);
|
||||
|
||||
return 0;
|
||||
}
|
||||
12
Examples/concurrency/Makefile
Normal file
12
Examples/concurrency/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
CC=gcc
|
||||
CFLAGS=-O0 -Wall -Wextra -g -pthread
|
||||
|
||||
BINS=$(patsubst %.c,%,$(wildcard *.c))
|
||||
|
||||
all: $(BINS)
|
||||
|
||||
clean:
|
||||
rm -f $(BINS)
|
||||
|
||||
%: %.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
57
Examples/concurrency/README.md
Normal file
57
Examples/concurrency/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Concurrency examples
|
||||
|
||||
CS3841 examples using concurrency techniques
|
||||
|
||||
Examples with file names con\*.c show the progression of problems that can arise by trying to perform mutual exclusion ourselves without OS support.
|
||||
|
||||
Other examples show in sem\*.c and mutex\*.c show how the OS can help out by providing concurrency mechanisms.
|
||||
|
||||
* race.c - Shows the race condition that can happen then threads try to modify multiple global values at the same time
|
||||
|
||||
* con1.c - Concurrency using "taking turns"
|
||||
Provides mutual exclusion but does not work for more than 2 processes
|
||||
Also does not work if a process does not want to access the critical section
|
||||
|
||||
* con2.c - Concurrency using flag array - version 1
|
||||
Allows threads to specify desire for critical secgion
|
||||
Due to race conditions with the flag array, it cannot guarentee mutual exclusion
|
||||
|
||||
* con3.c - Concurrency using flag array - version 2
|
||||
Move setting of the flag before the wait
|
||||
Allows threads to specify desire for critical secgion
|
||||
Due to race conditions with the flag array, it is prone to deadlock if both threads set the flag at the same time
|
||||
|
||||
* con4.c - Concurrency using flag array - version 3
|
||||
Sets the critical section flag before the wait
|
||||
Allows threads to specify desire for critical secgion
|
||||
Adds deadlock detection and relase of the flag if both threads have their flag set
|
||||
Prone to livelock since threads might be constantly releasing their flag
|
||||
|
||||
* con\_dekkers.c - Concurrency algorithm proposed by Theodorus Jozef Dekker
|
||||
Combines the deadlock detection of cons4 with the taking turns algorithm in cons1
|
||||
Ensures mutual exclusion along with deadlock/livelock prevention, however needs to know how many participants there are
|
||||
Also does not work on modern CPUs that perform out-of-order execution
|
||||
|
||||
* sem1.c - Uses semaphores to control access to the critical section
|
||||
|
||||
* sem2.c - Shows that semaphores are NOT locks, but a signalling mechanism. Multiple posts to a semaphore incremenet the count regardless of the current value
|
||||
|
||||
* sem\_list1.c - Shows what can happen as a result of uncontrolled access to a singly linked list
|
||||
|
||||
* sem\_list2.c - Uses a semaphore as a way to control access to a critical section for a singly linked list
|
||||
|
||||
* mutex1.c - Uses a mutex lock to control access to a critical section that increments two global variables
|
||||
|
||||
* mutex2.c - Shows the undefined behavior that can happen when a thread attempts to unlock a mutex that's already unlocked
|
||||
|
||||
* mutex3.c - Shows the deadlock behavior that can happen when a thread attempts to lock a mutex that it has already locked
|
||||
|
||||
* prod\_cons1.c - Shows the producer and consumer problem
|
||||
When access to a limited shared space is not controlled there are chances where a producer thread might attempt to write when the space is full and a consumer might attempt to read when the space is empty
|
||||
|
||||
* prod\_cons2.c - Shows the producer and consumer problem
|
||||
Access is controlled using semaphores
|
||||
One semaphore counts the number of filled spots
|
||||
One semaphore counts the number of empty spots
|
||||
Producers wait for at least one free spot before writing
|
||||
Consusmers wait for at least one filled spot before reading
|
||||
75
Examples/concurrency/con1.c
Normal file
75
Examples/concurrency/con1.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* con1.c - Concurrency using "taking turns"
|
||||
* Provides mutual exclusion but does not work for more than 2 processes
|
||||
* Also does not work if a process does not want to access the critical section
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// shared global
|
||||
static int counter1 = 0;
|
||||
static int counter2 = 0;
|
||||
|
||||
// start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// turn flag
|
||||
volatile int turn = 0;
|
||||
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int me = *((int *)args);
|
||||
int you = me ? 0 : 1;
|
||||
|
||||
printf("Worker thread: %d ready, you are %d\n", me, you);
|
||||
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for (int j = 0; j < 1000; j++)
|
||||
{
|
||||
while(turn != me)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
// this is the critical section
|
||||
counter1++;
|
||||
counter2++;
|
||||
// leaving critical section
|
||||
turn = you;
|
||||
}
|
||||
|
||||
printf("Worker thread: %d done\n", me);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int val1 = 0;
|
||||
int val2 = 1;
|
||||
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(thr1,NULL);
|
||||
pthread_join(thr2,NULL);
|
||||
|
||||
printf("counter1: %d\n",counter1);
|
||||
printf("counter2: %d\n",counter2);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
77
Examples/concurrency/con2.c
Normal file
77
Examples/concurrency/con2.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* con2.c - Concurrency using flag array - version 1
|
||||
* Allows threads to specify desire for critical secgion
|
||||
* Due to race conditions with the flag array, it cannot guarentee mutual exclusion
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// shared global
|
||||
static int counter1 = 0;
|
||||
static int counter2 = 0;
|
||||
|
||||
// start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// flag array
|
||||
volatile int flag[2] = {0,0};
|
||||
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int me = *((int *) args);
|
||||
int you = me ? 0 : 1;
|
||||
|
||||
printf("Worker thread: %d ready, you are %d\n",me,you);
|
||||
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for (int j = 0; j < 100000000; j++)
|
||||
{
|
||||
while(flag[you])
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
flag[me] = 1;
|
||||
// this is the critical section
|
||||
counter1++;
|
||||
counter2++;
|
||||
// leaving critical section
|
||||
flag[me] = 0;
|
||||
}
|
||||
|
||||
printf("Worker thread: %d done\n",me);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
int val1 = 0;
|
||||
int val2 = 1;
|
||||
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(thr1,NULL);
|
||||
pthread_join(thr2,NULL);
|
||||
|
||||
printf("counter1: %d\n",counter1);
|
||||
printf("counter2: %d\n",counter2);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
78
Examples/concurrency/con3.c
Normal file
78
Examples/concurrency/con3.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* con3.c - Concurrency using flag array - version 2
|
||||
* Move setting of the flag before the wait
|
||||
* Allows threads to specify desire for critical secgion
|
||||
* Due to race conditions with the flag array, it is prone to deadlock
|
||||
* if both threads set the flag at the same time
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// shared global
|
||||
static int counter1 = 0;
|
||||
static int counter2 = 0;
|
||||
|
||||
// start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// flag array
|
||||
volatile int flag[2] = {0,0};
|
||||
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int me = *((int *) args);
|
||||
int you = me ? 0 : 1;
|
||||
|
||||
printf("Worker thread: %d ready, you are %d\n",me,you);
|
||||
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for (int j = 0; j < 100000000; j++)
|
||||
{
|
||||
flag[me]=1;
|
||||
while(flag[you])
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
// this is the critical section
|
||||
counter1++;
|
||||
counter2++;
|
||||
// leaving critical section
|
||||
flag[me]=0;
|
||||
}
|
||||
|
||||
printf("Worker thread: %d done\n",me);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int val1 = 0;
|
||||
int val2 = 1;
|
||||
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(thr1,NULL);
|
||||
pthread_join(thr2,NULL);
|
||||
|
||||
printf("counter1: %d\n",counter1);
|
||||
printf("counter2: %d\n",counter2);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
84
Examples/concurrency/con4.c
Normal file
84
Examples/concurrency/con4.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* con4.c - Concurrency using flag array - version 3
|
||||
* Sets the critical section flag before the wait
|
||||
* Allows threads to specify desire for critical secgion
|
||||
* Adds deadlock detection and relase of the flag if both
|
||||
* threads have their flag set
|
||||
* Prone to livelock since threads might be constantly releasing their flag
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// shared global
|
||||
static int counter1 = 0;
|
||||
static int counter2 = 0;
|
||||
|
||||
// start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// flag array
|
||||
volatile int flag[2] = {0,0};
|
||||
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int me = *((int *) args);
|
||||
|
||||
int you = me ? 0 : 1;
|
||||
|
||||
printf("Worker thread: %d ready, you are %d\n",me,you);
|
||||
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for (int j = 0; j < 1000000; j++)
|
||||
{
|
||||
flag[me] = 1;
|
||||
while(flag[you])
|
||||
{
|
||||
// just in case there is deadlock
|
||||
flag[me] = 0;
|
||||
usleep(1); // enought time to allow other thread to run
|
||||
flag[me] = 1;
|
||||
}
|
||||
// this is the critical section
|
||||
counter1++;
|
||||
counter2++;
|
||||
// leaving critical section
|
||||
flag[me] = 0;
|
||||
}
|
||||
|
||||
printf("Worker thread: %d done\n",me);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
int val1 = 0;
|
||||
int val2 = 1;
|
||||
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(thr1,NULL);
|
||||
pthread_join(thr2,NULL);
|
||||
|
||||
printf("counter1: %d\n",counter1);
|
||||
printf("counter2: %d\n",counter2);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
91
Examples/concurrency/con_dekkers.c
Normal file
91
Examples/concurrency/con_dekkers.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* con_dekkers.c - Concurrency algorithm proposed by Theodorus Jozef Dekker
|
||||
* Combines the deadlock detection of cons4 with the
|
||||
* taking turns algorithm in cons1
|
||||
* Ensures mutual exclusion along with deadlock/livelock prevention
|
||||
* However needs to know how many participants there are
|
||||
* Also does not work on modern CPUs that perform out-of-order execution
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// shared global
|
||||
static int counter1 = 0;
|
||||
static int counter2 = 0;
|
||||
|
||||
// start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// turn flag
|
||||
volatile int turn = 0;
|
||||
|
||||
// flag array
|
||||
volatile int flag[2] = {0,0};
|
||||
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int me = *((int *) args);
|
||||
|
||||
int you = me ? 0 : 1;
|
||||
|
||||
printf("Worker thread: %d ready, you are %d\n",me,you);
|
||||
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for (int j = 0; j < 1000000; j++)
|
||||
{
|
||||
flag[me] = 1;
|
||||
while(flag[you])
|
||||
{
|
||||
if(turn == you)
|
||||
{
|
||||
// just in case there is deadlock
|
||||
flag[me] = 0;
|
||||
}
|
||||
while (turn == you);
|
||||
flag[me] = 1;
|
||||
}
|
||||
// this is the critical section
|
||||
counter1++;
|
||||
counter2++;
|
||||
// leaving critical section
|
||||
turn = you;
|
||||
flag[me] = 0;
|
||||
}
|
||||
|
||||
printf("Worker thread: %d done\n",me);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
int val1 = 0;
|
||||
int val2 = 1;
|
||||
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(thr1,NULL);
|
||||
pthread_join(thr2,NULL);
|
||||
|
||||
printf("counter1: %d\n",counter1);
|
||||
printf("counter2: %d\n",counter2);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
77
Examples/concurrency/mutex1.c
Normal file
77
Examples/concurrency/mutex1.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* mutex1.c - Uses a mutex lock to control access to a critical section
|
||||
* that increments two global variables
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// shared global
|
||||
static int counter1 = 0;
|
||||
static int counter2 = 0;
|
||||
|
||||
// start flag
|
||||
volatile int start;
|
||||
|
||||
// flag mutex
|
||||
pthread_mutex_t flag = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// The thread process
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int me = *((int *) args);
|
||||
|
||||
int you = me ? 0 : 1;
|
||||
|
||||
printf("Worker thread: %d ready, you are %d\n",me,you);
|
||||
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for (int j = 0; j < 1000000; j++)
|
||||
{
|
||||
pthread_mutex_lock(&flag);
|
||||
// this is the critical section
|
||||
counter1++;
|
||||
counter2++;
|
||||
// leaving critical section
|
||||
pthread_mutex_unlock(&flag);
|
||||
}
|
||||
|
||||
printf("Worker thread: %d done\n",me);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main process
|
||||
int main()
|
||||
{
|
||||
int val1 = 0;
|
||||
int val2 = 1;
|
||||
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(thr1,NULL);
|
||||
pthread_join(thr2,NULL);
|
||||
|
||||
printf("counter1: %d\n",counter1);
|
||||
printf("counter2: %d\n",counter2);
|
||||
|
||||
pthread_mutex_destroy(&flag);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
82
Examples/concurrency/mutex2.c
Normal file
82
Examples/concurrency/mutex2.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* mutex2.c - Shows the undefined behavior that can happen when
|
||||
* a thread attempts to unlock a mutex that's already
|
||||
* unlocked
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// shared global
|
||||
static int counter1 = 0;
|
||||
static int counter2 = 0;
|
||||
|
||||
// start flag
|
||||
volatile int start;
|
||||
|
||||
// flag mutex
|
||||
pthread_mutex_t flag = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// The thread process
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int me = *((int *) args);
|
||||
|
||||
int you = me ? 0 : 1;
|
||||
|
||||
printf("Worker thread: %d ready, you are %d\n",me,you);
|
||||
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for (int j = 0; j < 1000000; j++)
|
||||
{
|
||||
pthread_mutex_lock(&flag);
|
||||
// this is the critical section
|
||||
counter1++;
|
||||
counter2++;
|
||||
// leaving critical section
|
||||
pthread_mutex_unlock(&flag);
|
||||
|
||||
if(me == 0) {
|
||||
pthread_mutex_unlock(&flag);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Worker thread: %d done\n",me);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main process
|
||||
int main()
|
||||
{
|
||||
int val1 = 0;
|
||||
int val2 = 1;
|
||||
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(thr1,NULL);
|
||||
pthread_join(thr2,NULL);
|
||||
|
||||
printf("counter1: %d\n",counter1);
|
||||
printf("counter2: %d\n",counter2);
|
||||
|
||||
pthread_mutex_destroy(&flag);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
82
Examples/concurrency/mutex3.c
Normal file
82
Examples/concurrency/mutex3.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* mutex3.c - Shows the deadlock behavior that can happen when
|
||||
* a thread attempts to lock a mutex that it has already
|
||||
* locked
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// shared global
|
||||
static int counter1 = 0;
|
||||
static int counter2 = 0;
|
||||
|
||||
// start flag
|
||||
volatile int start;
|
||||
|
||||
// flag mutex
|
||||
pthread_mutex_t flag = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// The thread process
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int me = *((int *) args);
|
||||
|
||||
int you = me ? 0 : 1;
|
||||
|
||||
printf("Worker thread: %d ready, you are %d\n",me,you);
|
||||
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for (int j = 0; j < 1000000; j++)
|
||||
{
|
||||
pthread_mutex_lock(&flag);
|
||||
if(me == 0) {
|
||||
pthread_mutex_lock(&flag);
|
||||
}
|
||||
|
||||
// this is the critical section
|
||||
counter1++;
|
||||
counter2++;
|
||||
// leaving critical section
|
||||
pthread_mutex_unlock(&flag);
|
||||
}
|
||||
|
||||
printf("Worker thread: %d done\n",me);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main process
|
||||
int main()
|
||||
{
|
||||
int val1 = 0;
|
||||
int val2 = 1;
|
||||
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(thr1,NULL);
|
||||
pthread_join(thr2,NULL);
|
||||
|
||||
printf("counter1: %d\n",counter1);
|
||||
printf("counter2: %d\n",counter2);
|
||||
|
||||
pthread_mutex_destroy(&flag);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
114
Examples/concurrency/prod_cons1.c
Normal file
114
Examples/concurrency/prod_cons1.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* prod_cons1.c - Shows the producer and consumer problem
|
||||
* When access to a limited shared space is not
|
||||
* controlled there are chances where a producer thread
|
||||
* might attempt to write when the space is full and
|
||||
* a consumer might attempt to read when the space is empty
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#define BUFFER_SIZE 30
|
||||
#define ELEMENTS 100
|
||||
|
||||
// Shared Buffer
|
||||
typedef struct circular_buffer {
|
||||
unsigned char values[BUFFER_SIZE];
|
||||
int out_idx;
|
||||
int in_idx;
|
||||
} circular_buffer;
|
||||
|
||||
circular_buffer buffer;
|
||||
|
||||
void buffer_init(circular_buffer* b)
|
||||
{
|
||||
b->out_idx = 0;
|
||||
b->in_idx = 0;
|
||||
memset(b->values, 0, BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void buffer_insert(circular_buffer* b, unsigned char value)
|
||||
{
|
||||
if(b->values[b->in_idx] != 0) {
|
||||
printf("ERROR: Inserting into buffer when an element exists. Empty was expected\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
b->values[b->in_idx] = value;
|
||||
b->in_idx = b->in_idx < BUFFER_SIZE-1 ? b->in_idx + 1 : 0;
|
||||
}
|
||||
|
||||
unsigned char buffer_remove(circular_buffer* b)
|
||||
{
|
||||
unsigned char return_value = b->values[b->out_idx];
|
||||
if(return_value == 0) {
|
||||
printf("ERROR: Removing from a buffer at an empty element. Something was expected\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
b->values[b->out_idx] = 0;
|
||||
b->out_idx = b->out_idx < BUFFER_SIZE-1 ? b->out_idx + 1 : 0;
|
||||
return return_value;
|
||||
}
|
||||
|
||||
// Start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// Producer Routine
|
||||
void* producer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
// Add an element to the buffer
|
||||
unsigned char value = (i % 100) + 1; // Make sure the value isn't zero
|
||||
buffer_insert(&buffer, value);
|
||||
printf("Producer added: %d\n", value);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Consumer Routine
|
||||
void* consumer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
// Remove an element from the buffer
|
||||
printf("Consumer removed: %d\n", buffer_remove(&buffer));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main process
|
||||
int main()
|
||||
{
|
||||
buffer_init(&buffer);
|
||||
|
||||
pthread_t prod;
|
||||
pthread_t cons;
|
||||
if(pthread_create(&prod, NULL, producer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE PRODUCER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&cons, NULL, consumer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE CONSUMER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(prod, NULL);
|
||||
pthread_join(cons, NULL);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
136
Examples/concurrency/prod_cons2.c
Normal file
136
Examples/concurrency/prod_cons2.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* prod_cons1.c - Shows the producer and consumer problem
|
||||
* Access is controlled using semaphores
|
||||
* One semaphore counts the number of filled spots
|
||||
* One semaphore counts the number of empty spots
|
||||
* Producers wait for at least one free spot before writing
|
||||
* Consusmers wait for at least one filled spot before reading
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#define BUFFER_SIZE 30
|
||||
#define ELEMENTS 100
|
||||
|
||||
// Shared Buffer
|
||||
typedef struct circular_buffer {
|
||||
unsigned char values[BUFFER_SIZE];
|
||||
int out_idx;
|
||||
int in_idx;
|
||||
} circular_buffer;
|
||||
|
||||
circular_buffer buffer;
|
||||
|
||||
void buffer_init(circular_buffer* b)
|
||||
{
|
||||
b->out_idx = 0;
|
||||
b->in_idx = 0;
|
||||
memset(b->values, 0, BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void buffer_insert(circular_buffer* b, unsigned char value)
|
||||
{
|
||||
if(b->values[b->in_idx] != 0) {
|
||||
printf("ERROR: Inserting into buffer when an element exists. Empty was expected\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
b->values[b->in_idx] = value;
|
||||
b->in_idx = b->in_idx < BUFFER_SIZE-1 ? b->in_idx + 1 : 0;
|
||||
}
|
||||
|
||||
unsigned char buffer_remove(circular_buffer* b)
|
||||
{
|
||||
unsigned char return_value = b->values[b->out_idx];
|
||||
if(return_value == 0) {
|
||||
printf("ERROR: Removing from a buffer at an empty element. Something was expected\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
b->values[b->out_idx] = 0;
|
||||
b->out_idx = b->out_idx < BUFFER_SIZE-1 ? b->out_idx + 1 : 0;
|
||||
return return_value;
|
||||
}
|
||||
|
||||
// Semaphores for controlling access
|
||||
sem_t fullCount;
|
||||
sem_t emptyCount;
|
||||
|
||||
// Start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// Producer Routine
|
||||
void* producer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
// Wait for a free spot in the buffer
|
||||
sem_wait(&emptyCount);
|
||||
|
||||
// Add an element to the buffer
|
||||
unsigned char value = (i % 100) + 1; // Make sure the value isn't zero
|
||||
buffer_insert(&buffer, value);
|
||||
printf("Producer added: %d\n", value);
|
||||
|
||||
// Signal the consumer that there something to consume
|
||||
sem_post(&fullCount);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Consumer Routine
|
||||
void* consumer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
// Wait for element to consume
|
||||
sem_wait(&fullCount);
|
||||
|
||||
// Remove an element from the buffer
|
||||
printf("Consumer removed: %d\n", buffer_remove(&buffer));
|
||||
|
||||
// Signal the producer that there is a free spot
|
||||
sem_post(&emptyCount);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main process
|
||||
int main()
|
||||
{
|
||||
sem_init(&fullCount, 0, 0);
|
||||
sem_init(&emptyCount, 0, BUFFER_SIZE);
|
||||
buffer_init(&buffer);
|
||||
|
||||
pthread_t prod;
|
||||
pthread_t cons;
|
||||
if(pthread_create(&prod, NULL, producer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE PRODUCER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&cons, NULL, consumer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE CONSUMER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(prod, NULL);
|
||||
pthread_join(cons, NULL);
|
||||
|
||||
sem_destroy(&fullCount);
|
||||
sem_destroy(&emptyCount);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
68
Examples/concurrency/race.c
Normal file
68
Examples/concurrency/race.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* race.c - Shows the race condition that can happen
|
||||
* then threads try to modify multiple global
|
||||
* values at the same time
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// shared global
|
||||
static int counter1 = 0;
|
||||
static int counter2 = 0;
|
||||
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int me = *((int *)args);
|
||||
int you = me ? 0 : 1;
|
||||
|
||||
printf("Worker thread: %d ready, you are %d\n", me, you);
|
||||
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for (int j = 0; j < 100000000; j++)
|
||||
{
|
||||
// this is the critical section
|
||||
counter1++;
|
||||
counter2++;
|
||||
// leaving critical section
|
||||
}
|
||||
|
||||
printf("Worker thread: %d done\n",me);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int val1 = 0;
|
||||
int val2 = 1;
|
||||
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(thr1,NULL);
|
||||
pthread_join(thr2,NULL);
|
||||
|
||||
printf("counter1: %d\n",counter1);
|
||||
printf("counter2: %d\n",counter2);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
82
Examples/concurrency/sem1.c
Normal file
82
Examples/concurrency/sem1.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* sem1 - Uses semaphores to control access to the
|
||||
* critical section
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
// shared global
|
||||
static int counter1 = 0;
|
||||
static int counter2 = 0;
|
||||
|
||||
// start flag
|
||||
volatile int start;
|
||||
|
||||
// flag semaphore
|
||||
sem_t flag;
|
||||
|
||||
// The thread process
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int me = *((int *) args);
|
||||
|
||||
int you = me ? 0 : 1;
|
||||
|
||||
printf("Worker thread: %d ready, you are %d\n",me,you);
|
||||
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for (int j = 0; j < 1000000; j++)
|
||||
{
|
||||
sem_wait(&flag);
|
||||
// this is the critical section
|
||||
counter1++;
|
||||
counter2++;
|
||||
// leaving critical section
|
||||
sem_post(&flag);
|
||||
}
|
||||
|
||||
printf("Worker thread: %d done\n",me);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main process
|
||||
int main()
|
||||
{
|
||||
int val1 = 0;
|
||||
int val2 = 1;
|
||||
|
||||
// Initialize the semaphore - initial value of 1
|
||||
sem_init(&flag, 0, 1);
|
||||
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(thr1,NULL);
|
||||
pthread_join(thr2,NULL);
|
||||
|
||||
printf("counter1: %d\n",counter1);
|
||||
printf("counter2: %d\n",counter2);
|
||||
|
||||
// Destroy the semaphore
|
||||
sem_destroy(&flag);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
85
Examples/concurrency/sem2.c
Normal file
85
Examples/concurrency/sem2.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* sem2.c - Shows that semaphores are NOT locks, but a signalling
|
||||
* mechanism. Multiple posts to a semaphore incremenet
|
||||
* the count regardless of the current value
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
// shared global
|
||||
static int counter1 = 0;
|
||||
static int counter2 = 0;
|
||||
|
||||
// start flag
|
||||
volatile int start;
|
||||
|
||||
// flag semaphore
|
||||
sem_t flag;
|
||||
|
||||
// The thread process
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int me = *((int *) args);
|
||||
|
||||
int you = me ? 0 : 1;
|
||||
|
||||
printf("Worker thread: %d ready, you are %d\n",me,you);
|
||||
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for (int j = 0; j < 100000000; j++)
|
||||
{
|
||||
sem_wait(&flag);
|
||||
// this is the critical section
|
||||
counter1++;
|
||||
counter2++;
|
||||
// leaving critical section
|
||||
sem_post(&flag);
|
||||
|
||||
if(me == 0) {
|
||||
sem_post(&flag);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Worker thread: %d done\n",me);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main process
|
||||
int main()
|
||||
{
|
||||
int val1 = 0;
|
||||
int val2 = 1;
|
||||
|
||||
sem_init(&flag, 0, 1);
|
||||
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(thr1,NULL);
|
||||
pthread_join(thr2,NULL);
|
||||
|
||||
printf("counter1: %d\n",counter1);
|
||||
printf("counter2: %d\n",counter2);
|
||||
|
||||
sem_destroy(&flag);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
90
Examples/concurrency/sem_list1.c
Normal file
90
Examples/concurrency/sem_list1.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* sem_list1.c - Shows what can happen as a result of
|
||||
* uncontrolled access to a singly linked list
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
typedef struct node {
|
||||
int val;
|
||||
struct node* next;
|
||||
} node;
|
||||
|
||||
typedef struct list {
|
||||
node* head;
|
||||
} list;
|
||||
|
||||
// shared global
|
||||
static list mylist;
|
||||
|
||||
// start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// The thread process
|
||||
void* thread_routine()
|
||||
{
|
||||
printf("Worker thread: %lu ready\n", pthread_self());
|
||||
|
||||
// wait for start from master thread
|
||||
while(start == 0);
|
||||
|
||||
for (int j = 0; j < 1000000; j++)
|
||||
{
|
||||
node* new_node = malloc(sizeof(node));
|
||||
new_node->val = j;
|
||||
new_node->next = mylist.head;
|
||||
mylist.head = new_node;
|
||||
}
|
||||
|
||||
printf("Worker thread: %lu done\n", pthread_self());
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Main process
|
||||
int main()
|
||||
{
|
||||
#define THREAD_COUNT 10
|
||||
pthread_t thr_ids[THREAD_COUNT];
|
||||
|
||||
mylist.head = NULL;
|
||||
|
||||
// Create the threads
|
||||
for(int i = 0; i < THREAD_COUNT; i++) {
|
||||
if(pthread_create(&thr_ids[i], NULL, thread_routine, NULL) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Signal threads to start
|
||||
start = 1;
|
||||
|
||||
// Wait for all threads to finish
|
||||
for(int i = 0; i < THREAD_COUNT; i++) {
|
||||
pthread_join(thr_ids[i],NULL);
|
||||
}
|
||||
|
||||
// Count the elements in the list
|
||||
int length = 0;
|
||||
node* itr = mylist.head;
|
||||
while(itr != NULL) {
|
||||
length++;
|
||||
itr = itr->next;
|
||||
}
|
||||
printf("List contains %d elements\n", length);
|
||||
|
||||
// Free the list
|
||||
while(mylist.head != NULL) {
|
||||
node* to_delete = mylist.head;
|
||||
mylist.head = mylist.head->next;
|
||||
free(to_delete);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
99
Examples/concurrency/sem_list2.c
Normal file
99
Examples/concurrency/sem_list2.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* sem_list2.c - Uses a semaphore as a way to control access
|
||||
* to a critical section for a singly linked list
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
typedef struct node {
|
||||
int val;
|
||||
struct node* next;
|
||||
} node;
|
||||
|
||||
typedef struct list {
|
||||
node* head;
|
||||
} list;
|
||||
|
||||
// shared global
|
||||
static list mylist;
|
||||
|
||||
// start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// flag semaphore
|
||||
sem_t flag;
|
||||
|
||||
// The thread process
|
||||
void* thread_routine()
|
||||
{
|
||||
printf("Worker thread: %lu ready\n", pthread_self());
|
||||
|
||||
// wait for start from master thread
|
||||
while(start == 0);
|
||||
|
||||
for (int j = 0; j < 1000000; j++)
|
||||
{
|
||||
sem_wait(&flag);
|
||||
node* new_node = malloc(sizeof(node));
|
||||
new_node->val = j;
|
||||
new_node->next = mylist.head;
|
||||
mylist.head = new_node;
|
||||
sem_post(&flag);
|
||||
}
|
||||
|
||||
printf("Worker thread: %lu done\n", pthread_self());
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Main process
|
||||
int main()
|
||||
{
|
||||
sem_init(&flag, 0, 1);
|
||||
|
||||
#define THREAD_COUNT 10
|
||||
pthread_t thr_ids[THREAD_COUNT];
|
||||
|
||||
mylist.head = NULL;
|
||||
|
||||
// Create the threads
|
||||
for(int i = 0; i < THREAD_COUNT; i++) {
|
||||
if(pthread_create(&thr_ids[i], NULL, thread_routine, NULL) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Signal threads to start
|
||||
start = 1;
|
||||
|
||||
// Wait for all threads to finish
|
||||
for(int i = 0; i < THREAD_COUNT; i++) {
|
||||
pthread_join(thr_ids[i],NULL);
|
||||
}
|
||||
|
||||
// Count the elements in the list
|
||||
int length = 0;
|
||||
node* itr = mylist.head;
|
||||
while(itr != NULL) {
|
||||
length++;
|
||||
itr = itr->next;
|
||||
}
|
||||
printf("List contains %d elements\n", length);
|
||||
|
||||
// Free the list
|
||||
while(mylist.head != NULL) {
|
||||
node* to_delete = mylist.head;
|
||||
mylist.head = mylist.head->next;
|
||||
free(to_delete);
|
||||
}
|
||||
|
||||
sem_destroy(&flag);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
12
Examples/conditions/Makefile
Normal file
12
Examples/conditions/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
CC=gcc
|
||||
CFLAGS=-O0 -Wall -Wextra -g -pthread
|
||||
|
||||
BINS=$(patsubst prod_con%.c,prod_con%,$(wildcard prod_con*.c))
|
||||
|
||||
all: $(BINS)
|
||||
|
||||
clean:
|
||||
rm -f $(BINS)
|
||||
|
||||
%: %.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
38
Examples/conditions/README.md
Normal file
38
Examples/conditions/README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Producer/Consumer with condition variable examples
|
||||
|
||||
CS3841 examples for producer/consumer that motivate the need for condition variables
|
||||
|
||||
* prod\_con1.c - Producer and consumer with unlimited sized buffer
|
||||
Works with a single semaphore to count full slots when only a single producer and consumer is used
|
||||
|
||||
* prod\_con2.c - Producer and consumer with unlimited sized buffer
|
||||
Shows a problem that can arise when multiple consumers are consuming elements from the shared space at the same time
|
||||
With no controlled access between consumers, the number of elements in the shared space become incorrect
|
||||
|
||||
* prod\_con3.c - Producer and consumer with unlimited sized buffer
|
||||
Fixes the problem when multiple producers and consumers modify a shared space by using a mutex lock to prevent threads from modifying the space at the same time
|
||||
|
||||
* prod\_con4.c - Producer and consumer with unlimited sized buffer
|
||||
Shows a problem that can arise when a consumer wants to consume multiple items from the shared space. Since a mutex lock is used to lock out other threads, it is possible for a consumer to remove elements from an empty shared space
|
||||
|
||||
* prod\_con5.c - Producer and consumer with unlimited sized buffer
|
||||
An attempt to fix the problem of a consumer removing from an empty shared space when more than one item is to be consumed by waiting in a while loop until enough elements are in the space
|
||||
Unfortunately causes deadlock since the consumer is holding the the mutex lock while waiting for more items
|
||||
|
||||
* prod\_con6.c - Producer and consumer with unlimited sized buffer
|
||||
An attempt to fix the problem of a consumer removing from an empty shared space when more than one item is to be consumed by waiting in a while loop until enough elements are in the space.
|
||||
Attemps to fix the deadlock provlem in prod\_cons5.c by releasing the lock
|
||||
Unfortunately the consumer releasing the lock in the while loop causes undefined behavior
|
||||
|
||||
* prod\_con7.c - Producer and consumer with unlimited sized buffer
|
||||
An attempt to fix the problem of a consumer removing from an empty shared space when more than one item is to be consumed by releasing the lock on the shared space and then waiting on a semaphore until there are more items.
|
||||
Unfortunately, there is know way for the consumer to get back into the "head of the line" after more items are produced. Another consumer can skip ahead
|
||||
|
||||
* prod\_con\_cond1.c - Producer and consumer with unlimited sized buffer
|
||||
Uses a condition variable to ensure proper order of the consumers when they wait for more items to be consumed
|
||||
Unfortunately, using a single condition variable without additional mutual exculsion does not maintain the consumers order in line
|
||||
|
||||
* prod\_con\_cond2.c - Producer and consumer with unlimited sized buffer
|
||||
Uses a condition variable to ensure proper order of the consumers when they wait for more items to be consumed
|
||||
Also uses a mutex to control the ordering of consumers
|
||||
This example provides correct behavior when there are multiple producers and multiple consumers and each consumer orders multiple items.
|
||||
95
Examples/conditions/prod_con1.c
Normal file
95
Examples/conditions/prod_con1.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* prod_con1.c - Producer and consumer with unlimited sized buffer
|
||||
* Works with a single semaphore to count full slots
|
||||
* when only a single producer and consumer is used
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#define ELEMENTS 100
|
||||
|
||||
int count = 0;
|
||||
|
||||
// Semaphores for controlling access
|
||||
sem_t fullCount;
|
||||
|
||||
// Start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// Producer Routine
|
||||
void* producer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
|
||||
// Add an element
|
||||
count++;
|
||||
printf("Producer %lu added, count: %d\n", pthread_self(), count);
|
||||
|
||||
// Signal the consumer that there something to consume
|
||||
sem_post(&fullCount);
|
||||
usleep(200);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Consumer Routine
|
||||
void* consumer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
// Wait for element to consume
|
||||
sem_wait(&fullCount);
|
||||
|
||||
// Remove an element from the buffer
|
||||
if(count == 0) {
|
||||
printf("ERROR: Customer %lu removed with no elements\n", pthread_self());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
count--;
|
||||
usleep(50);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main thread
|
||||
int main()
|
||||
{
|
||||
sem_init(&fullCount, 0, 0);
|
||||
|
||||
pthread_t prod;
|
||||
pthread_t cons;
|
||||
|
||||
if(pthread_create(&prod, NULL, producer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE PRODUCER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&cons, NULL, consumer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE CONSUMER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
pthread_join(prod, NULL);
|
||||
pthread_join(cons, NULL);
|
||||
|
||||
printf("Final count is: %d, expected 0\n", count);
|
||||
|
||||
sem_destroy(&fullCount);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
108
Examples/conditions/prod_con2.c
Normal file
108
Examples/conditions/prod_con2.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* prod_con2.c - Producer and consumer with unlimited sized buffer
|
||||
* Shows a problem that can arise when multiple consumers
|
||||
* are consuming elements from the shared space at the same time
|
||||
* With no controlled access between consumers, the number
|
||||
* of elements in the shared space become incorrect
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#define ELEMENTS 100
|
||||
#define PRODUCER_COUNT 10
|
||||
#define CONSUMER_COUNT 5
|
||||
|
||||
int count = 0;
|
||||
|
||||
// Semaphores for controlling access
|
||||
sem_t fullCount;
|
||||
|
||||
// Start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// Producer Routine
|
||||
void* producer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
|
||||
// Add an element
|
||||
count++;
|
||||
printf("Producer %lu added, count: %d\n", pthread_self(), count);
|
||||
|
||||
// Signal the consumer that there something to consume
|
||||
sem_post(&fullCount);
|
||||
usleep(200);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Consumer Routine
|
||||
void* consumer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
// Wait for element to consume
|
||||
sem_wait(&fullCount);
|
||||
|
||||
// Remove an element from the buffer
|
||||
if(count == 0) {
|
||||
printf("ERROR: Customer %lu removed with no elements\n", pthread_self());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
count--;
|
||||
usleep(50);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main thread
|
||||
int main()
|
||||
{
|
||||
sem_init(&fullCount, 0, 0);
|
||||
|
||||
pthread_t prod[PRODUCER_COUNT];
|
||||
pthread_t cons[CONSUMER_COUNT];
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
if(pthread_create(&prod[i], NULL, producer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE PRODUCER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
if(pthread_create(&cons[i], NULL, consumer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE CONSUMER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
pthread_join(prod[i], NULL);
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
pthread_join(cons[i], NULL);
|
||||
}
|
||||
|
||||
int expected_final_count = PRODUCER_COUNT*ELEMENTS - CONSUMER_COUNT*ELEMENTS;
|
||||
|
||||
printf("Final count is: %d, expected %d\n", count, expected_final_count);
|
||||
|
||||
sem_destroy(&fullCount);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
116
Examples/conditions/prod_con3.c
Normal file
116
Examples/conditions/prod_con3.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* prod_con3.c - Producer and consumer with unlimited sized buffer
|
||||
* Fixes the problem when multiple producers and
|
||||
* consumers modify a shared space by using
|
||||
* a mutex lock to prevent threads from modifying
|
||||
* the space at the same time
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#define ELEMENTS 100
|
||||
#define PRODUCER_COUNT 10
|
||||
#define CONSUMER_COUNT 5
|
||||
|
||||
int count = 0;
|
||||
|
||||
// Semaphores for controlling access
|
||||
sem_t fullCount;
|
||||
|
||||
pthread_mutex_t element_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// Start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// Producer Routine
|
||||
void* producer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
// Add an element
|
||||
count++;
|
||||
printf("Producer %lu added, count: %d\n", pthread_self(), count);
|
||||
|
||||
// Signal the consumer that there something to consume
|
||||
sem_post(&fullCount);
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
usleep(200);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Consumer Routine
|
||||
void* consumer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
// Wait for element to consume
|
||||
sem_wait(&fullCount);
|
||||
|
||||
// Remove an element from the buffer
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
if(count == 0) {
|
||||
printf("ERROR: Customer %lu removed with no elements\n", pthread_self());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
count--;
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
usleep(50);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main thread
|
||||
int main()
|
||||
{
|
||||
sem_init(&fullCount, 0, 0);
|
||||
|
||||
pthread_t prod[PRODUCER_COUNT];
|
||||
pthread_t cons[CONSUMER_COUNT];
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
if(pthread_create(&prod[i], NULL, producer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE PRODUCER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
if(pthread_create(&cons[i], NULL, consumer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE CONSUMER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
pthread_join(prod[i], NULL);
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
pthread_join(cons[i], NULL);
|
||||
}
|
||||
|
||||
int expected_final_count = PRODUCER_COUNT*ELEMENTS - CONSUMER_COUNT*ELEMENTS;
|
||||
|
||||
printf("Final count is: %d, expected %d\n", count, expected_final_count);
|
||||
|
||||
sem_destroy(&fullCount);
|
||||
pthread_mutex_destroy(&element_mutex);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
119
Examples/conditions/prod_con4.c
Normal file
119
Examples/conditions/prod_con4.c
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* prod_con4.c - Producer and consumer with unlimited sized buffer
|
||||
* Shows a problem that can arise when a consumer
|
||||
* wants to consume multiple items from the shared
|
||||
* space. Since a mutex lock is used to lock out
|
||||
* other threads, it is possible for a consumer
|
||||
* to remove elements from an empty shared space
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#define ELEMENTS 100
|
||||
#define PRODUCER_COUNT 10
|
||||
#define CONSUMER_COUNT 5
|
||||
#define ORDER_COUNT 2
|
||||
|
||||
int count = 0;
|
||||
|
||||
// Semaphores for controlling access
|
||||
sem_t fullCount;
|
||||
|
||||
pthread_mutex_t element_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// Start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// Producer Routine
|
||||
void* producer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
// Add an element
|
||||
count++;
|
||||
printf("Producer %lu added, count: %d\n", pthread_self(), count);
|
||||
|
||||
// Signal the consumer that there something to consume
|
||||
sem_post(&fullCount);
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
usleep(200);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Consumer Routine
|
||||
void* consumer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
// Wait for element to consume
|
||||
sem_wait(&fullCount);
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
for(int j = 0; j < ORDER_COUNT; j++) {
|
||||
// Remove an element from the buffer
|
||||
if(count == 0) {
|
||||
printf("ERROR: Customer %lu removed with no elements\n", pthread_self());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
count--;
|
||||
}
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
usleep(50);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main thread
|
||||
int main()
|
||||
{
|
||||
sem_init(&fullCount, 0, 0);
|
||||
|
||||
pthread_t prod[PRODUCER_COUNT];
|
||||
pthread_t cons[CONSUMER_COUNT];
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
if(pthread_create(&prod[i], NULL, producer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE PRODUCER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
if(pthread_create(&cons[i], NULL, consumer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE CONSUMER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
pthread_join(prod[i], NULL);
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
pthread_join(cons[i], NULL);
|
||||
}
|
||||
|
||||
int expected_final_count = PRODUCER_COUNT*ELEMENTS - CONSUMER_COUNT*ELEMENTS*ORDER_COUNT;
|
||||
|
||||
printf("Final count is: %d, expected %d\n", count, expected_final_count);
|
||||
|
||||
sem_destroy(&fullCount);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
123
Examples/conditions/prod_con5.c
Normal file
123
Examples/conditions/prod_con5.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* prod_con5.c - Producer and consumer with unlimited sized buffer
|
||||
* An attempt to fix the problem of a consumer removing
|
||||
* from an empty shared space when more than one item
|
||||
* is to be consumed by waiting in a while loop until
|
||||
* enough elements are in the space
|
||||
* Unfortunately causes deadlock since the consumer is
|
||||
* holding the the mutex lock while waiting for more items
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#define ELEMENTS 100
|
||||
#define PRODUCER_COUNT 10
|
||||
#define CONSUMER_COUNT 5
|
||||
#define ORDER_COUNT 2
|
||||
|
||||
int count = 0;
|
||||
|
||||
// Semaphores for controlling access
|
||||
sem_t fullCount;
|
||||
|
||||
pthread_mutex_t element_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// Start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// Producer Routine
|
||||
void* producer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
// Add an element
|
||||
count++;
|
||||
printf("Producer %lu added, count: %d\n", pthread_self(), count);
|
||||
|
||||
// Signal the consumer that there something to consume
|
||||
sem_post(&fullCount);
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
usleep(200);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Consumer Routine
|
||||
void* consumer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
// Wait for element to consume
|
||||
sem_wait(&fullCount);
|
||||
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
while(count < ORDER_COUNT);
|
||||
|
||||
for(int j = 0; j < ORDER_COUNT; j++) {
|
||||
// Remove an element from the buffer
|
||||
if(count == 0) {
|
||||
printf("ERROR: Customer %lu removed with no elements\n", pthread_self());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
count--;
|
||||
}
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
usleep(50);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main thread
|
||||
int main()
|
||||
{
|
||||
sem_init(&fullCount, 0, 0);
|
||||
|
||||
pthread_t prod[PRODUCER_COUNT];
|
||||
pthread_t cons[CONSUMER_COUNT];
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
if(pthread_create(&prod[i], NULL, producer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE PRODUCER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
if(pthread_create(&cons[i], NULL, consumer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE CONSUMER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
pthread_join(prod[i], NULL);
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
pthread_join(cons[i], NULL);
|
||||
}
|
||||
|
||||
int expected_final_count = PRODUCER_COUNT*ELEMENTS - CONSUMER_COUNT*ELEMENTS;
|
||||
|
||||
printf("Final count is: %d, expected %d\n", count, expected_final_count);
|
||||
|
||||
sem_destroy(&fullCount);
|
||||
pthread_mutex_destroy(&element_mutex);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
127
Examples/conditions/prod_con6.c
Normal file
127
Examples/conditions/prod_con6.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* prod_con6.c - Producer and consumer with unlimited sized buffer
|
||||
* An attempt to fix the problem of a consumer removing
|
||||
* from an empty shared space when more than one item
|
||||
* is to be consumed by waiting in a while loop until
|
||||
* enough elements are in the space. Attemps to fix the
|
||||
* deadlock provlem in prod_cons5.c by releasing the lock
|
||||
* Unfortunately the consumer releasing the lock in the
|
||||
* while loop causes undefined behavior
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#define ELEMENTS 100
|
||||
#define PRODUCER_COUNT 10
|
||||
#define CONSUMER_COUNT 5
|
||||
#define ORDER_COUNT 2
|
||||
|
||||
int count = 0;
|
||||
|
||||
// Semaphores for controlling access
|
||||
sem_t fullCount;
|
||||
|
||||
pthread_mutex_t element_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// Start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// Producer Routine
|
||||
void* producer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
// Add an element
|
||||
count++;
|
||||
printf("Producer %lu added, count: %d\n", pthread_self(), count);
|
||||
|
||||
// Signal the consumer that there something to consume
|
||||
sem_post(&fullCount);
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
usleep(200);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Consumer Routine
|
||||
void* consumer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
// Wait for element to consume
|
||||
sem_wait(&fullCount);
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
while(count < ORDER_COUNT) {
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
}
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
for(int j = 0; j < ORDER_COUNT; j++) {
|
||||
// Remove an element from the buffer
|
||||
if(count == 0) {
|
||||
printf("ERROR: Customer %lu removed with no elements\n", pthread_self());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
count--;
|
||||
}
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
usleep(50);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main thread
|
||||
int main()
|
||||
{
|
||||
sem_init(&fullCount, 0, 0);
|
||||
|
||||
pthread_t prod[PRODUCER_COUNT];
|
||||
pthread_t cons[CONSUMER_COUNT];
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
if(pthread_create(&prod[i], NULL, producer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE PRODUCER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
if(pthread_create(&cons[i], NULL, consumer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE CONSUMER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
pthread_join(prod[i], NULL);
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
pthread_join(cons[i], NULL);
|
||||
}
|
||||
|
||||
int expected_final_count = PRODUCER_COUNT*ELEMENTS - CONSUMER_COUNT*ELEMENTS;
|
||||
|
||||
printf("Final count is: %d, expected %d\n", count, expected_final_count);
|
||||
|
||||
sem_destroy(&fullCount);
|
||||
pthread_mutex_destroy(&element_mutex);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
131
Examples/conditions/prod_con7.c
Normal file
131
Examples/conditions/prod_con7.c
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* prod_con7.c - Producer and consumer with unlimited sized buffer
|
||||
* An attempt to fix the problem of a consumer removing
|
||||
* from an empty shared space when more than one item
|
||||
* is to be consumed by releasing the lock on the shared
|
||||
* space and then waiting on a semaphore until there
|
||||
* are more items.
|
||||
* Unfortunately, there is know way for the consumer
|
||||
* to get back into the "head of the line" after more
|
||||
* items are produced. Another consumer can skip ahead
|
||||
* and take the items.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#define ELEMENTS 100
|
||||
#define PRODUCER_COUNT 10
|
||||
#define CONSUMER_COUNT 5
|
||||
#define ORDER_COUNT 2
|
||||
|
||||
int count = 0;
|
||||
|
||||
// Semaphores for controlling access
|
||||
sem_t fullCount;
|
||||
|
||||
pthread_mutex_t element_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// Start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// Producer Routine
|
||||
void* producer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
// Add an element
|
||||
count++;
|
||||
printf("Producer %lu added, count: %d\n", pthread_self(), count);
|
||||
|
||||
// Signal the consumer that there something to consume
|
||||
sem_post(&fullCount);
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
usleep(200);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Consumer Routine
|
||||
void* consumer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
// Wait for element to consume
|
||||
sem_wait(&fullCount);
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
for(int j = 0; j < ORDER_COUNT; j++) {
|
||||
|
||||
if(count == 0) {
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
sem_wait(&fullCount);
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
}
|
||||
|
||||
// Remove an element from the buffer
|
||||
if(count == 0) {
|
||||
printf("ERROR: Customer %lu removed with no elements\n", pthread_self());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
count--;
|
||||
}
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
usleep(50);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main thread
|
||||
int main()
|
||||
{
|
||||
sem_init(&fullCount, 0, 0);
|
||||
|
||||
pthread_t prod[PRODUCER_COUNT];
|
||||
pthread_t cons[CONSUMER_COUNT];
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
if(pthread_create(&prod[i], NULL, producer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE PRODUCER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
if(pthread_create(&cons[i], NULL, consumer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE CONSUMER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
pthread_join(prod[i], NULL);
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
pthread_join(cons[i], NULL);
|
||||
}
|
||||
|
||||
int expected_final_count = PRODUCER_COUNT*ELEMENTS - CONSUMER_COUNT*ELEMENTS;
|
||||
|
||||
printf("Final count is: %d, expected %d\n", count, expected_final_count);
|
||||
|
||||
sem_destroy(&fullCount);
|
||||
pthread_mutex_destroy(&element_mutex);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
121
Examples/conditions/prod_con_cond1.c
Normal file
121
Examples/conditions/prod_con_cond1.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* prod_con_cond1.c - Producer and consumer with unlimited sized buffer
|
||||
* Uses a condition variable to ensure proper
|
||||
* order of the consumers when they wait for more
|
||||
* items to be consumed.
|
||||
* Unfortunately, using a single condition variable
|
||||
* without additional mutual exculsion does not maintain
|
||||
* the consumers order in line
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define ELEMENTS 100
|
||||
#define PRODUCER_COUNT 10
|
||||
#define CONSUMER_COUNT 5
|
||||
#define ORDER_COUNT 2
|
||||
|
||||
int count = 0;
|
||||
|
||||
pthread_mutex_t element_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t has_elements = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
// Start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// Producer Routine
|
||||
void* producer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
// Add an element
|
||||
count++;
|
||||
printf("Producer %lu added, count: %d\n", pthread_self(), count);
|
||||
|
||||
// Signal the consumer that there is something to consume
|
||||
pthread_cond_signal(&has_elements);
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
|
||||
usleep(200);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Consumer Routine
|
||||
void* consumer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
for(int j = 0; j < ORDER_COUNT; j++) {
|
||||
|
||||
// Wait for element to consume
|
||||
if(count == 0) {
|
||||
pthread_cond_wait(&has_elements, &element_mutex);
|
||||
}
|
||||
|
||||
// Remove an element
|
||||
if(count == 0) {
|
||||
printf("ERROR: Customer %lu removed with no elements\n", pthread_self());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
count--;
|
||||
}
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
|
||||
usleep(50);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main thread
|
||||
int main()
|
||||
{
|
||||
pthread_t prod[PRODUCER_COUNT];
|
||||
pthread_t cons[CONSUMER_COUNT];
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
if(pthread_create(&prod[i], NULL, producer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE PRODUCER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < 5; i++) {
|
||||
if(pthread_create(&cons[i], NULL, consumer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE CONSUMER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
pthread_join(prod[i], NULL);
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
pthread_join(cons[i], NULL);
|
||||
}
|
||||
|
||||
printf("Final count is: %d\n", count);
|
||||
|
||||
pthread_cond_destroy(&has_elements);
|
||||
pthread_mutex_destroy(&element_mutex);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
133
Examples/conditions/prod_con_cond2.c
Normal file
133
Examples/conditions/prod_con_cond2.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* prod_con_cond2.c - Producer and consumer with unlimited sized buffer
|
||||
* Uses a condition variable to ensure proper
|
||||
* order of the consumers when they wait for more
|
||||
* items to be consumed.
|
||||
* Also uses a mutex to control the ordering of consumers
|
||||
* This example provides correct behavior when there
|
||||
* are multiple producers and multiple consumers and each
|
||||
* consumer orders multiple items.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define ELEMENTS 100
|
||||
#define PRODUCER_COUNT 10
|
||||
#define CONSUMER_COUNT 5
|
||||
#define ORDER_COUNT 2
|
||||
|
||||
int count = 0;
|
||||
|
||||
pthread_mutex_t consumer_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_t element_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t has_elements = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
// Start flag
|
||||
volatile int start = 0;
|
||||
|
||||
// Producer Routine
|
||||
void* producer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
// Add an element
|
||||
count++;
|
||||
printf("Producer %lu added, count: %d\n", pthread_self(), count);
|
||||
|
||||
// Signal the consumer that there is something to consume
|
||||
pthread_cond_signal(&has_elements);
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
|
||||
usleep(200);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Consumer Routine
|
||||
void* consumer()
|
||||
{
|
||||
// wait for start from master thread
|
||||
while(!start);
|
||||
|
||||
for(int i = 0; i < ELEMENTS; i++) {
|
||||
|
||||
// All consumers line up in order
|
||||
pthread_mutex_lock(&consumer_mutex);
|
||||
|
||||
// Only one consumer gets to be at the head of the line
|
||||
pthread_mutex_lock(&element_mutex);
|
||||
|
||||
for(int j = 0; j < ORDER_COUNT; j++) {
|
||||
|
||||
// Wait for element to consume
|
||||
if(count == 0) {
|
||||
pthread_cond_wait(&has_elements, &element_mutex);
|
||||
}
|
||||
|
||||
// Remove an element
|
||||
if(count == 0) {
|
||||
printf("ERROR: Customer %lu removed with no elements\n", pthread_self());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
count--;
|
||||
}
|
||||
|
||||
// Let more consumers and producers run
|
||||
pthread_mutex_unlock(&element_mutex);
|
||||
|
||||
// Let the next consumer at the head of the line order items
|
||||
pthread_mutex_unlock(&consumer_mutex);
|
||||
|
||||
usleep(50);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Main thread
|
||||
int main()
|
||||
{
|
||||
pthread_t prod[PRODUCER_COUNT];
|
||||
pthread_t cons[CONSUMER_COUNT];
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
if(pthread_create(&prod[i], NULL, producer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE PRODUCER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < 5; i++) {
|
||||
if(pthread_create(&cons[i], NULL, consumer, NULL) == -1) {
|
||||
printf("COULD NOT CREATE CONSUMER\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
start = 1;
|
||||
|
||||
for(int i = 0; i < PRODUCER_COUNT; i++) {
|
||||
pthread_join(prod[i], NULL);
|
||||
}
|
||||
for(int i = 0; i < CONSUMER_COUNT; i++) {
|
||||
pthread_join(cons[i], NULL);
|
||||
}
|
||||
|
||||
printf("Final count is: %d\n", count);
|
||||
|
||||
pthread_cond_destroy(&has_elements);
|
||||
pthread_mutex_destroy(&element_mutex);
|
||||
pthread_mutex_destroy(&consumer_mutex);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Binary file not shown.
39
Examples/ipc/ipcmsg_gfg_r.c
Normal file
39
Examples/ipc/ipcmsg_gfg_r.c
Normal file
@@ -0,0 +1,39 @@
|
||||
// C Program for Message Queue (Reader Process)
|
||||
#include <stdio.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
// structure for message queue
|
||||
struct mesg_buffer
|
||||
{
|
||||
long mesg_type;
|
||||
char mesg_text[100];
|
||||
} message;
|
||||
|
||||
int main()
|
||||
{
|
||||
key_t key;
|
||||
int msgid;
|
||||
|
||||
// ftok to generate unique key
|
||||
key = ftok("progfile", 65);
|
||||
|
||||
// msgget creates a message queue
|
||||
// and returns identifier
|
||||
msgid = msgget(key, 0666 | IPC_CREAT);
|
||||
|
||||
// msgrcv to receive message
|
||||
msgrcv(msgid, &message, sizeof(message), 0, 0);
|
||||
printf("Data Received is : %s \n", message.mesg_text);
|
||||
msgrcv(msgid, &message, sizeof(message), 0, 0);
|
||||
printf("Data Received is : %s \n", message.mesg_text);
|
||||
msgrcv(msgid, &message, sizeof(message), 0, 0);
|
||||
printf("Data Received is : %s \n", message.mesg_text);
|
||||
msgrcv(msgid, &message, sizeof(message), 0, 0);
|
||||
printf("Data Received is : %s \n", message.mesg_text);
|
||||
|
||||
// to destroy the message queue
|
||||
msgctl(msgid, IPC_RMID, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
46
Examples/ipc/ipcmsg_gfg_s.c
Normal file
46
Examples/ipc/ipcmsg_gfg_s.c
Normal file
@@ -0,0 +1,46 @@
|
||||
// C Program for Message Queue (Writer Process)
|
||||
#include <stdio.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#define MAX 10
|
||||
|
||||
// structure for message queue
|
||||
struct mesg_buffer
|
||||
{
|
||||
long mesg_type;
|
||||
char mesg_text[100];
|
||||
} m1, m2, m3, m4;
|
||||
|
||||
int main()
|
||||
{
|
||||
key_t key;
|
||||
int msgid;
|
||||
|
||||
// ftok to generate unique key
|
||||
key = ftok("progfile", 65);
|
||||
|
||||
// msgget creates a message queue
|
||||
// and returns identifier
|
||||
msgid = msgget(key, 0666 | IPC_CREAT);
|
||||
m1.mesg_type = 1;
|
||||
m2.mesg_type = 2;
|
||||
m3.mesg_type = 3;
|
||||
m4.mesg_type = 4;
|
||||
|
||||
printf("Write Data : ");
|
||||
fgets(m1.mesg_text, MAX, stdin);
|
||||
fgets(m2.mesg_text, MAX, stdin);
|
||||
fgets(m3.mesg_text, MAX, stdin);
|
||||
fgets(m4.mesg_text, MAX, stdin);
|
||||
|
||||
// msgsnd to send message
|
||||
msgsnd(msgid, &m1, sizeof(m1), 0);
|
||||
msgsnd(msgid, &m2, sizeof(m2), 0);
|
||||
msgsnd(msgid, &m3, sizeof(m3), 0);
|
||||
msgsnd(msgid, &m4, sizeof(m4), 0);
|
||||
|
||||
// display the message
|
||||
// printf("Data send is : %s \n", message.mesg_text);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3,12 +3,12 @@
|
||||
* to send a signal from one process to another
|
||||
*/
|
||||
|
||||
#include <signal.h> // needed for signal system call
|
||||
#include <stdio.h> // needed for printf, perror
|
||||
#include <stdlib.h> // needed for exit
|
||||
#include <sys/types.h> // needed for pid_t
|
||||
#include <sys/wait.h> // needed for wait system call
|
||||
#include <unistd.h> // needed for fork, getpid, getppid, kill system calls
|
||||
#include <stdlib.h> // needed for exit
|
||||
#include <signal.h> // needed for signal system call
|
||||
#include <stdio.h> // needed for printf, perror
|
||||
|
||||
void signal_handler(int sig)
|
||||
{
|
||||
@@ -23,12 +23,12 @@ int main()
|
||||
|
||||
pid_t pid = fork(); // fork into 2 processes
|
||||
|
||||
if(pid < 0) // error
|
||||
if (pid < 0) // error
|
||||
{
|
||||
perror("fork");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if(pid == 0) // child
|
||||
else if (pid == 0) // child
|
||||
{
|
||||
// Send a signal to the parent by its PID
|
||||
pid_t parent_pid = getppid();
|
||||
|
||||
BIN
Examples/ipc/rec
Executable file
BIN
Examples/ipc/rec
Executable file
Binary file not shown.
BIN
Examples/ipc/send
Executable file
BIN
Examples/ipc/send
Executable file
Binary file not shown.
12
Examples/pthreads/Makefile
Normal file
12
Examples/pthreads/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
CC=gcc
|
||||
CFLAGS=-Wall -Wextra -g -pthread
|
||||
|
||||
BINS=$(patsubst %.c,%,$(wildcard *.c))
|
||||
|
||||
all: $(BINS)
|
||||
|
||||
clean:
|
||||
rm -f $(BINS)
|
||||
|
||||
%: %.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
27
Examples/pthreads/README.md
Normal file
27
Examples/pthreads/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# pthread examples
|
||||
|
||||
CS3841 examples using the pthread library to create POSIX threads
|
||||
|
||||
* pthreads1.c - Shows how to create and wait for single thread (beyond the main thread)
|
||||
|
||||
* pthreads2.c - Shows how to create and wait for multple threads (beyond the main thread)
|
||||
Threads prints out its thread ID and process ID
|
||||
Shows that threads share the same process ID but all have their own thread ID
|
||||
|
||||
* pthreads3.c - Shows how to pass parameter values to thread routines
|
||||
|
||||
* pthreads4.c - Shows how to pass parameter values to thread routines
|
||||
The threads dereference the pointer passed to the thread routine to demonstrate that memory is shared between all threads
|
||||
|
||||
* pthreads5.c - Shows a problem that can happen with parameters passed to thread routines due to the fact that the parameter must be a pointer
|
||||
The referenced location must be valid for the entire life of the thread
|
||||
NOTE: Context switches between threads can happen when unexpected
|
||||
|
||||
* pthreads6.c - Shows the problems that can happen due to the fact that thread routine parameters are pointers to memory locations
|
||||
Threads can easily affect other threads memory
|
||||
NOTE: Context switches between threads can happen when unexpected
|
||||
|
||||
* pthreads\_race.c - Shows a "race condition" when multiple threads try to race to modify a global value
|
||||
Due to unpredictable behavior in context switching the value of global\_value does not result in what is expected
|
||||
|
||||
* pthreads\_race\_atomic.c - Uses an atomic add instruction to prevent the race condition that can happen when multiple threads modify a global value at the same time
|
||||
48
Examples/pthreads/pthreads1.c
Normal file
48
Examples/pthreads/pthreads1.c
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* pthreads1.c - Shows how to create and wait for single
|
||||
* thread (beyond the main thread)
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int global_value = 10;
|
||||
|
||||
// thread_routine
|
||||
// writes to a global variable - shows that
|
||||
// global data is shared between threads
|
||||
//
|
||||
// NOTE: that parameters and return value are pointers
|
||||
void* thread_routine()
|
||||
{
|
||||
for(int i = 0; i < 10; i++) {
|
||||
printf("THREAD READS GLOBAL VALUE: %d\n", global_value);
|
||||
global_value++;
|
||||
sleep(1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Create a thread
|
||||
pthread_t thr_id;
|
||||
if(pthread_create(&thr_id, NULL, thread_routine, NULL) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Write to global data
|
||||
for(int i = 0; i < 10; i++) {
|
||||
printf("PARENT READS GLOBAL: %d\n", global_value);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
// Wait for thread to finish
|
||||
pthread_join(thr_id, NULL);
|
||||
|
||||
// Return success
|
||||
return 0;
|
||||
}
|
||||
52
Examples/pthreads/pthreads2.c
Normal file
52
Examples/pthreads/pthreads2.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* pthreads2.c - Shows how to create and wait for multple
|
||||
* threads (beyond the main thread)
|
||||
* Threads prints out its thread ID and process ID.
|
||||
* Shows that threads share the same process ID
|
||||
* but all have their own thread ID
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int global_value = 10;
|
||||
|
||||
// thread_routine
|
||||
// writes to a global variable - shows that
|
||||
// global data is shared between threads
|
||||
//
|
||||
// NOTE: that parameters and return value are pointers
|
||||
void* thread_routine()
|
||||
{
|
||||
for(int i = 0; i < 10; i++) {
|
||||
printf("%lu %d: THREAD READS GLOBAL VALUE: %d\n", pthread_self(), getpid(), global_value);
|
||||
global_value++;
|
||||
sleep(1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Create 5 threads
|
||||
pthread_t thr_id[5];
|
||||
for(int i = 0; i < 5; i++) {
|
||||
if(pthread_create(&thr_id[i], NULL, thread_routine, NULL) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for all threads to finish
|
||||
for(int i = 0; i < 5; i++) {
|
||||
pthread_join(thr_id[i], NULL);
|
||||
}
|
||||
|
||||
// Print out final value of global data
|
||||
printf("%lu %d PARENT READS GLOBAL: %d\n", pthread_self(), getpid(), global_value);
|
||||
|
||||
// Return success
|
||||
return 0;
|
||||
}
|
||||
60
Examples/pthreads/pthreads3.c
Normal file
60
Examples/pthreads/pthreads3.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* pthreads3.c - Shows how to pass parameter values to thread routines
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Function to check if a number is prime
|
||||
// Returns 1 if prime, 0 if not prime
|
||||
int is_prime(int v)
|
||||
{
|
||||
for(int i = 2; i < v; i++) {
|
||||
if(v % i == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Thread routine
|
||||
// calls is_prime to check if the input argument is prime
|
||||
//
|
||||
// NOTE: that parameters and return value are pointers
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int* val = (int*)args;
|
||||
if(is_prime(*val)) {
|
||||
printf("THREAD %lu FOUND that %d is prime\n", pthread_self(), *val);
|
||||
} else {
|
||||
printf("THREAD %lu FOUND that %d is not prime\n", pthread_self(), *val);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int val1 = 2;
|
||||
int val2 = 100;
|
||||
|
||||
// Create 2 threads, passing a different value to each
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Wait for the threads to finish
|
||||
pthread_join(thr1, NULL);
|
||||
pthread_join(thr2, NULL);
|
||||
|
||||
// Return success
|
||||
return 0;
|
||||
}
|
||||
72
Examples/pthreads/pthreads4.c
Normal file
72
Examples/pthreads/pthreads4.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* pthreads4.c - Shows how to pass parameter values to thread routines
|
||||
* The threads dereference the pointer passed to the
|
||||
* thread routine to demonstrate that memory is shared
|
||||
* between all threads
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Function to check if a number is prime
|
||||
// Returns 1 if prime, 0 if not prime
|
||||
int is_prime(int v)
|
||||
{
|
||||
for(int i = 2; i < v; i++) {
|
||||
if(v % i == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Thread routine
|
||||
// calls is_prime to check if the input argument is prime
|
||||
// Modifies the input parameter by dereferencing the pointer
|
||||
//
|
||||
// NOTE: that parameters and return value are pointers
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int* val = (int*)args;
|
||||
if(is_prime(*val)) {
|
||||
printf("THREAD %lu FOUND that %d is prime\n", pthread_self(), *val);
|
||||
*val = 1;
|
||||
} else {
|
||||
printf("THREAD %lu FOUND that %d is not prime\n", pthread_self(), *val);
|
||||
*val = 0;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int val1 = 2;
|
||||
int val2 = 100;
|
||||
|
||||
// Print out the values before creating threads
|
||||
printf("Parent val1=%d val2=%d\n", val1, val2);
|
||||
|
||||
// Create 2 threads
|
||||
pthread_t thr1;
|
||||
pthread_t thr2;
|
||||
if(pthread_create(&thr1, NULL, thread_routine, (void*)&val1) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(pthread_create(&thr2, NULL, thread_routine, (void*)&val2) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Wait for the threads to finish
|
||||
pthread_join(thr1, NULL);
|
||||
pthread_join(thr2, NULL);
|
||||
|
||||
// Print out the final values
|
||||
printf("Parent val1=%d val2=%d\n", val1, val2);
|
||||
|
||||
// Return success
|
||||
return 0;
|
||||
}
|
||||
66
Examples/pthreads/pthreads5.c
Normal file
66
Examples/pthreads/pthreads5.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* pthreads5.c - Shows a problem that can happen with parameters
|
||||
* passed to thread routines due to the fact that
|
||||
* the parameter must be a pointer. The referenced
|
||||
* location must be valid for the entire life of the
|
||||
* thread.
|
||||
*
|
||||
* NOTE: Context switches between threads can happen when unexpected
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Function to check if a number is prime
|
||||
// Returns 1 if prime, 0 if not prime
|
||||
int is_prime(int v)
|
||||
{
|
||||
for(int i = 2; i < v; i++) {
|
||||
if(v % i == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Thread routine
|
||||
// calls is_prime to check if the input argument is prime
|
||||
//
|
||||
// NOTE: that parameters and return value are pointers
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int* val = (int*)args;
|
||||
if(is_prime(*val)) {
|
||||
printf("THREAD %lu FOUND that %d is prime\n", pthread_self(), *val);
|
||||
} else {
|
||||
printf("THREAD %lu FOUND that %d is not prime\n", pthread_self(), *val);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// start_thread
|
||||
// Creates a new thread and returns the thread ID
|
||||
//
|
||||
// NOTE: the parameter to the thread is created on the stack
|
||||
// the address becomes invalid when the function returns
|
||||
pthread_t start_thread(int val)
|
||||
{
|
||||
pthread_t thr;
|
||||
printf("Before thread creation val=%d\n", val);
|
||||
if(pthread_create(&thr, NULL, thread_routine, (void*)&val) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return thr;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t thr1 = start_thread(2);
|
||||
pthread_t thr2 = start_thread(100);
|
||||
pthread_join(thr1, NULL);
|
||||
pthread_join(thr2, NULL);
|
||||
return 0;
|
||||
}
|
||||
68
Examples/pthreads/pthreads6.c
Normal file
68
Examples/pthreads/pthreads6.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* pthreads6.c - Shows the problems that can happen due to the fact
|
||||
* that thread routine parameters are pointers to memory
|
||||
* locations. Threads can easily affect other threads
|
||||
* memory.
|
||||
*
|
||||
* NOTE: Context switches between threads can happen when unexpected
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Function to check if a number is prime
|
||||
// Returns 1 if prime, 0 if not prime
|
||||
int is_prime(int v)
|
||||
{
|
||||
for(int i = 2; i < v; i++) {
|
||||
if(v % i == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Thread routine
|
||||
// calls is_prime to check if the input argument is prime
|
||||
// Modifies the input parameter by dereferencing the pointer
|
||||
//
|
||||
// NOTE: that parameters and return value are pointers
|
||||
void* thread_routine(void* args)
|
||||
{
|
||||
int* val = (int*)args;
|
||||
if(is_prime(*val)) {
|
||||
printf("THREAD %lu FOUND that %d is prime %p\n", pthread_self(), *val, val);
|
||||
*val = 1;
|
||||
} else {
|
||||
printf("THREAD %lu FOUND that %d is not prime %p\n", pthread_self(), *val, val);
|
||||
*val = 0;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int val = 0;
|
||||
|
||||
// Create 10 threads
|
||||
pthread_t thr[10];
|
||||
for(int i = 0; i < 10; i++) {
|
||||
|
||||
// NOTE: there is a single memory location for val which is passed to all threads
|
||||
val = i + 2;
|
||||
if(pthread_create(&thr[i], NULL, thread_routine, (void*)&val) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for threads to finish
|
||||
for(int i = 0; i < 10; i++) {
|
||||
pthread_join(thr[i], NULL);
|
||||
}
|
||||
|
||||
// Return success
|
||||
return 0;
|
||||
}
|
||||
46
Examples/pthreads/pthreads_race.c
Normal file
46
Examples/pthreads/pthreads_race.c
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* pthreads_race.c - Shows a "race condition" when multiple threads
|
||||
* try to race to modify a global value
|
||||
* Due to unpredictable behavior in context switching
|
||||
* the value of global_value does not result in what is
|
||||
* expected
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int global_value = 0;
|
||||
|
||||
void* thread_routine()
|
||||
{
|
||||
for(int i = 0; i < 100000000; i++) {
|
||||
global_value++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Create 5 threads
|
||||
pthread_t thr_id[5];
|
||||
for(int i = 0; i < 5; i++) {
|
||||
if(pthread_create(&thr_id[i], NULL, thread_routine, NULL) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for all threads to finish
|
||||
for(int i = 0; i < 5; i++) {
|
||||
pthread_join(thr_id[i], NULL);
|
||||
}
|
||||
|
||||
// Print out final value of global value
|
||||
// 5 threads * 100000000 iterations - expected value is 500000000
|
||||
printf("PARENT READS GLOBAL: %d\n", global_value);
|
||||
|
||||
// Return success
|
||||
return 0;
|
||||
}
|
||||
46
Examples/pthreads/pthreads_race_atomic.c
Normal file
46
Examples/pthreads/pthreads_race_atomic.c
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* pthreads_race_atomic.c - Uses an atomic add instruction to prevent
|
||||
* the race condition that can happen when
|
||||
* multiple threads modify a global value at the
|
||||
* same time.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
atomic_int global_value = 0;
|
||||
|
||||
void* thread_routine()
|
||||
{
|
||||
for(int i = 0; i < 100000000; i++) {
|
||||
atomic_fetch_add(&global_value, 1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Create 5 threads
|
||||
pthread_t thr_id[5];
|
||||
for(int i = 0; i < 5; i++) {
|
||||
if(pthread_create(&thr_id[i], NULL, thread_routine, NULL) == -1) {
|
||||
printf("COULD NOT CREATE A THREAD\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for all threads to finish
|
||||
for(int i = 0; i < 5; i++) {
|
||||
pthread_join(thr_id[i], NULL);
|
||||
}
|
||||
|
||||
// Print out final value of global value
|
||||
// 5 threads * 100000000 iterations - expected value is 500000000
|
||||
printf("PARENT READS GLOBAL: %d\n", global_value);
|
||||
|
||||
// Return success
|
||||
return 0;
|
||||
}
|
||||
BIN
Notes/CS3841-02-OSIntro.pdf
Normal file
BIN
Notes/CS3841-02-OSIntro.pdf
Normal file
Binary file not shown.
BIN
Notes/CS3841-03-OSStructuresSystemCalls.pdf
Normal file
BIN
Notes/CS3841-03-OSStructuresSystemCalls.pdf
Normal file
Binary file not shown.
BIN
Notes/CS3841-05-IPC.pdf
Normal file
BIN
Notes/CS3841-05-IPC.pdf
Normal file
Binary file not shown.
BIN
Notes/CS3841-06-Threads.pdf
Normal file
BIN
Notes/CS3841-06-Threads.pdf
Normal file
Binary file not shown.
BIN
Notes/CS3841-07-Concurrency.pdf
Normal file
BIN
Notes/CS3841-07-Concurrency.pdf
Normal file
Binary file not shown.
BIN
Notes/CS3841-08-Deadlock.pdf
Normal file
BIN
Notes/CS3841-08-Deadlock.pdf
Normal file
Binary file not shown.
BIN
Notes/CS3841-09-Scheduling.pdf
Normal file
BIN
Notes/CS3841-09-Scheduling.pdf
Normal file
Binary file not shown.
BIN
Notes/CS3841-10-MemoryManagement.pdf
Normal file
BIN
Notes/CS3841-10-MemoryManagement.pdf
Normal file
Binary file not shown.
BIN
Notes/CS3841-11-FileSystems.pdf
Normal file
BIN
Notes/CS3841-11-FileSystems.pdf
Normal file
Binary file not shown.
Reference in New Issue
Block a user