-
Notifications
You must be signed in to change notification settings - Fork 0
aaroneponymous/Kanpsack-Parallel
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Assignment 1 Aaron Paul [email protected] Project Directory includes: 1. build/ - contains build files after running cmake -S .. 2. inputs/ - contains txt files with weights and values to be used as inputs in thee executables 3. output/ - serial_results.cpp: Runs the serial knapsack function on each input file 10 times and outputs a "serial_results.txt" file which contains the Max Value returned by the function and execution time for each iteration and the average execution time of those 10 iterations (executable: serial_results) - parallel_results.cpp: Runs the parallel knapsack function on each input file 10 times and outputs a "parallel_results.txt" file which contains the Max Value returned by the function and execution time for each iteration and the execution time of those 10 iterations (executable: parallel_results) 4. src/ - knapsack_parallel.cpp: Implementation of the parallel knapsack function, and a main routine which accepts an input txt file number of threads to run the problem on, prints out the max value returned and the time taken for the program to finish - knapsack_serial.cpp: Implementation of the serial knapsack function, and a main routine which accepts an input txt file and prints the max value returned and the time taken to execute the function 5. CMakeLists.txt - For generating build - make - files Building & Running Executables: The executables are already compiled and present in the top-level directory, however if you'd like to build the executables from scratch follow these directions: Run these commands in the Project Directory sequentially: (Remove any Makefile/CMake log file(s) present in the build/): > cd build/ && rm -rf * && cmake -S .. && make && cd .. Alternatively, > rm -rf build/ (if present) > mkdir build/ > cd build/ && cmake -S .. && make && cd .. Commands to run executables: 1. To Output Results of Serial Algorithm on Inputs (already present) > ./serial_results 2. To Output Results of Parallel Algorithm on Inputs (already present) > ./parallel_results 3. To run Serial Algorithm on user-provided inputs > ./knapsack_serial <input-file> 4. To run Parallel Algorithm on user-provided inputs > ./knapsack_parallel <input-file> <no-of-threads> Parallel Knapsack Program (see knapsack_parallel.cpp) Implementation Details The implementation is divided into two main parts: the Barrier class and the parallel_knapsack function. Barrier Class The Barrier class is a synchronization primitive that can be used to synchronize threads. It allows multiple threads to wait for each other to reach a certain point in their execution (the barrier), before they all continue execution. The Barrier class uses a std::mutex for mutual exclusion and a std::condition_variable for blocking and waking up threads. It also keeps track of the number of threads that need to reach the barrier (barrier_threads), the number of threads that have not yet reached the barrier (pending_threads_), and the generation of the barrier (barrier_gen_). The Wait function is used by a thread to indicate that it has reached the barrier. If it is the last thread to reach the barrier, it resets the barrier and wakes up all other threads. If it is not the last thread, it blocks until all other threads have reached the barrier. Parallel Knapsack Function (Algorithm) The parallel_knapsack function solves the 0/1 Knapsack problem using a bottom-up dynamic programming approach. The breakdown is as follows: Initialization: Two vectors prev_dp and curr_dp are initialized to store the maximum value that can be obtained for each capacity from 0 to the given capacity. They are initially filled with zeros. The prev_dp vector represents the maximum value for the previous item, while curr_dp represents the maximum value for the current item. Iteration: The function iterates over each item (from 1 to n). For each item, it creates num_threads threads. Each thread is responsible for a range of capacities. Computation: For each capacity within the range of a thread, it checks if the current item can be included in the knapsack (i.e., its weight is less than or equal to the capacity). If it can, it updates curr_dp[w] to be the maximum of prev_dp[w] (the maximum value without including the current item) and prev_dp[w - weights[row - 1]] + values[row - 1] (the maximum value including the current item). If the current item cannot be included, curr_dp[w] is set to prev_dp[w]. Synchronization: After each thread has computed the DP values for its range of capacities, it waits at the barrier until all threads have reached the barrier. This ensures that all threads have finished their computation before moving on to the next item. Joining Threads: After all threads have been created and started, the function waits for all of them to finish execution using thread.join(). Swapping DP Arrays: After all threads have finished execution for the current item, the function swaps prev_dp and curr_dp. This makes the current DP array become the previous DP array for the next item, and resets the current DP array to its initial state. Result: After all items have been processed, the function returns the maximum value that can be included in the knapsack, which is prev_dp[capacity]. C++ Multi-Threading Features Used: std::thread std::mutex In my implementation, the mutex is used in the Barrier class to ensure that the threads don't interfere with each other when updating the pending_threads_ and barrier_gen_ variables. std::condition_variable This is used in conjunction with a std::unique_lock to wait for a condition to become true. The condition variable is used in the Barrier class to make threads wait until all threads have reached the barrier. std::unique_lock This is a lock that owns and manages the locking and unlocking of a mutex. The unique lock is used in the Barrier class to lock the mutex when a thread reaches the barrier and to unlock it when all threads have reached the barrier. Lambda functions I use a lambda function to define the task that each thread should perform. std::thread::join() Barrier Synchronization: Implemented in Barrier class.
About
No description, website, or topics provided.
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published