I have been given the homework of making 5 threads as "philosophers" and each of them has to lock "eat" 2 synchronization locks simultaneously. Each thread must do this a million times.
The other part of this homework is to make the "philosophers" processes, and the locks mutex's.
I have made this code for the threaded part, and while it does technically work, the result isn't what I'd expect. The code has a logging system in which a red [NUM-x] means NUM thread attempted to lock two locks and failed to do so. And a green [NUM1-NUM2] means NUM1 thread successfully locked and unlocked 2 threads for the NUM2'd time.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>
#define CHOPSTICKS 5
#define PEOPLE 5
#define EAT_AMOUNT 1000000
#define MIN 2
#define INVALID -1
#define PAUSE printf("\n\n"); system("pause")
CRITICAL_SECTION chopsticks[CHOPSTICKS];
HANDLE chopsticksMutex[CHOPSTICKS]; // used for the mutex part of this question
VOID WINAPI eatThreadCritSect(LPVOID params) {
int index[MIN] = { 0 };
int usage = 0;
BOOL usageFlag = FALSE;
for (int i = 0; i < MIN; i++) {
index[i] = INVALID;
}
for (int i = 0; i < EAT_AMOUNT; i++) {
while (usage != MIN) {
for (int j = 0; j < CHOPSTICKS; j++) {
for (int k = 0; k < MIN && !usageFlag; k++) {
if (index[k] == j) {
usageFlag = TRUE;
}
}
if (!usageFlag) {
for (int k = 0; k < MIN && !usageFlag; k++) {
if (index[k] == INVALID) {
if (TryEnterCriticalSection(&chopsticks[j])) {
index[k] = j;
usage++;
}
usageFlag = TRUE;
}
}
}
usageFlag = FALSE;
}
for (int j = 0; j < MIN; j++) {
if (index[j] != INVALID) {
LeaveCriticalSection(&chopsticks[index[j]]);
index[j] = INVALID;
}
}
if (usage != MIN) {
printf("\x1b[31m[%d-X]", (int)params + 1); // CHOPSTICKS UNAVAILABLE
usage = 0;
}
}
printf("\x1b[32m[%d-%d]", ((int)params + 1), i + 1); // ATE SUCCESSFULLY
usage = 0;
}
}
void criticalEat() {
HANDLE hThreads[PEOPLE];
time_t begin = time(NULL);
for (int i = 0; i < PEOPLE; i++) {
hThreads[i] = CreateThread(NULL, 0, eatThreadCritSect, i, 0, NULL);
}
for (int i = 0; i < PEOPLE; i++) {
if (hThreads[i]) {
WaitForSingleObject(hThreads[i], INFINITE);
CloseHandle(hThreads[i]);
}
}
time_t end = time(NULL);
printf("\n\n\x1b[0mThey're now very saturated. It took them %llu seconds to eat with critical sections.", (end - begin));
}
void mutexEat() { // used for the mutex part of this question
PROCESS_INFORMATION hProcesses[PEOPLE];
CHAR name[] = "philosopher.exe 0";
time_t begin = time(NULL);
for (int i = 0; i < PEOPLE; i++) {
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
name[strlen(name) - 1] = i + '0';
CreateProcessA("philosopher.exe", name, NULL, NULL, FALSE, 0, NULL, NULL, &si, &hProcesses[i]);
}
for (int i = 0; i < PEOPLE; i++) {
WaitForSingleObject(hProcesses[i].hProcess, INFINITE);
CloseHandle(hProcesses[i].hThread);
CloseHandle(hProcesses[i].hProcess);
}
time_t end = time(NULL);
printf("\n\n\x1b[0mThey're now extremely fat and about to explode. It took them %llu seconds to eat with mutex's.", (end - begin));
}
int main() {
// used for the mutex part of this question
CHAR name[] = { "STICK_0" };
for (int i = 0; i < CHOPSTICKS; i++) {
name[strlen(name) - 1] = '0' + (i + 1);
InitializeCriticalSection(&chopsticks[i]);
chopsticksMutex[i] = CreateMutexA(NULL, FALSE, name);
}
criticalEat();
PAUSE;
mutexEat();
for (int i = 0; i < CHOPSTICKS; i++) {
DeleteCriticalSection(&chopsticks[i]);
if (chopsticksMutex[i]) { // preventing annoying warning
CloseHandle(chopsticksMutex[i]);
}
}
printf("\n\nI'm honestly surprised they made it. Why are we torturing philosophers?");
PAUSE;
return 0;
}
If I run this code, it will in a very technical sense work. However, the logged results show only green success logs, leading me to believe one of the lock checks is flawed. However, if I try to run the program in debug mode with breakpoints, and run it very slowly, red unsuccessful logs do appear. The same thing happens if I add a Sleep(1). Red logs appear. I believe red logs should appear regardless of these slowing measures, since 5 threads are trying to access 5 locks at the same time, each thread taking 2 locks for themselves.
As for the mutex part, here it is:
#include <Windows.h>
#include <stdio.h>
#define CHOPSTICKS 5
#define MIN 2
#define INVALID -1
#define EAT_AMOUNT 1000000
int main(int argc, char** argv) {
HANDLE chopsticksMutex[CHOPSTICKS];
int index[MIN] = { 0 };
int usage = 0;
BOOL usageFlag = FALSE;
CHAR name[] = { "STICK_0" };
for (int i = 0; i < CHOPSTICKS; i++) {
name[strlen(name) - 1] = '0' + (i + 1);
chopsticksMutex[i] = CreateMutexA(NULL, FALSE, name);
}
for (int i = 0; i < MIN; i++) {
index[i] = INVALID;
}
for (int i = 0; i < EAT_AMOUNT; i++) {
while (usage != MIN) {
for (int j = 0; j < CHOPSTICKS; j++) {
for (int k = 0; k < MIN && !usageFlag; k++) {
if (index[k] == j) {
usageFlag = TRUE;
}
}
if (!usageFlag) {
for (int k = 0; k < MIN && !usageFlag; k++) {
if (index[k] == INVALID) {
if (WaitForSingleObject(chopsticksMutex[j], 0) != WAIT_ABANDONED) {
index[k] = j;
usage++;
}
usageFlag = TRUE;
}
}
}
usageFlag = FALSE;
}
for (int j = 0; j < MIN; j++) {
if (index[j] != INVALID) {
ReleaseMutex(chopsticksMutex[index[j]]);
index[j] = INVALID;
}
}
if (usage != MIN) {
printf("\x1b[31m[%c-X]", argv[1][0] + 1); // CHOPSTICKS UNAVAILABLE
usage = 0;
}
}
printf("\x1b[32m[%c-%d]", argv[1][0], i + 1); // ATE SUCCESSFULLY
usage = 0;
}
return 0;
}
Now, from what I've been taught, Mutex locks, in general, are slower. But here again, there are no red logs indicating that there was a failed attempt to lock 2 locks, and the Mutex implementation is faster, even though it makes no sense.
Does what I'm saying even make any sense? In multi-threaded programming, should I expect this behaviour? I'm pretty sure I should expect a couple of red logs, without intentionally bottlenecking the program.
Related
So I have a project where I needed to implement the game of life and then parallelise it in c. However, when I try using pthreads.h to parallelise it the program runs slower when introducing more threads and the %CPU is lower than 100% (when using top in the ubuntu terminal, I have an Ubuntu Windows subsystem). Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
/* Parallel code with PTHREADS v1 */
//Global variables
int N; // Size of the world
int nthreads; // Number of threads
pthread_mutex_t lock;
typedef struct info_thread
{
int threadID; // thread ID
int low; // lower limit of interval
int high; // higher limit of interval
int **world; // pointer to the world matrix
int **neighbors; // pointer to the neighbors matrix
//int **neighbors_2; // pointer to the neighbors_2 matrix
//int **one_step; // pointer to the one_step matrix
}t_info;
void * thread_func(void *arg);
void print_world(int **world);
void count_neighbors(int **world, int **neighbors);
void next_step(int **world, int **one_step, int **neighbors);
void update(int **world, int **one_step);
int compare(int **world, int **one_step, int **two_steps, int **old, int status);
int main(int argc, const char *argv[])
{
if (argc != 5)
{
printf("Give the following input arguments:\n");
printf("N: Size of the NxN world (integer)\n");
printf("Initial state: random (0), chessboard (1)\n");
printf("Output: Number of steps until final state (0) \n");
printf(" Number of steps until final state, initial and final states (1) \n");
printf(" Number of steps until final state and all states states (2) \n");
printf("Threads: Number of threads (integer)\n");
exit(0);
}
N = atoi(argv[1]);
const int pattern = atoi(argv[2]);
const int output = atoi(argv[3]);
nthreads = atoi(argv[4]);
// Create necessary matrices
const int n = N+1;
int **buffer = (int **)malloc(6 * n * sizeof(int *));
for(int i = 0; i < (6*n); i++)
{
buffer[i] = (int *)malloc(n*sizeof(int));
}
int **world = &buffer[0];
int **neighbors = &buffer[n];
int **neighbors_2 = &buffer[2*n];
int **one_step = &buffer[3*n];
int **two_steps = &buffer[4*n];
int **old = &buffer[5*n];
// Setting a random initial pattern
if(pattern == 0){
srand(time(0));
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
int r = rand() % 10;
if (r > 5)
world[i][j] = 1;
else
world[i][j] = 0;
}
}
}
// Setting a chessboard initial state
else if(pattern == 1){
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if(i%2 == 0){
if(j%2 == 0)
world[i][j] = 0;
else
world[i][j] = 1;
}
else{
if(j%2 == 0)
world[i][j] = 1;
else
world[i][j] = 0;
}
}
}
}
if(output==1 || output==2){
printf("Initial state:\n");
print_world(world);
}
int status = 1;
int t = 1;
update(old, world);
// Create threads and input info
pthread_t thread[nthreads];
t_info threadinfo[nthreads];
const int interval = N/nthreads;
while(status == 1)
{
for (int k=0; k<nthreads; k++)
{
threadinfo[k].threadID = k;
threadinfo[k].low = k*interval;
threadinfo[k].high = (k+1)*interval-1;
threadinfo[k].world = world;
threadinfo[k].neighbors = neighbors;
}
threadinfo[nthreads-1].high = N;
// Predict one step forward
pthread_mutex_init(&lock, NULL);
for (int k=0; k<nthreads; k++)
pthread_create(&thread[k], NULL, thread_func, (void *)&threadinfo[k]);
for (int k=0; k<nthreads; k++)
pthread_join(thread[k],NULL);
pthread_mutex_destroy(&lock);
next_step(world, one_step, neighbors);
// Predict two steps forward
for (int k=0; k<nthreads; k++)
{
threadinfo[k].world = one_step;
threadinfo[k].neighbors = neighbors_2;
}
for (int k=0; k<nthreads; k++)
pthread_create(&thread[k], NULL, thread_func, (void *)&threadinfo[k]);
for (int k=0; k<nthreads; k++)
pthread_join(thread[k],NULL);
//count_neighbors(one_step,neighbors_2);
next_step(one_step, two_steps, neighbors_2);
// Compare all predicted steps
status = compare(world, one_step, two_steps, old, status);
// Update world with two steps
update(world, two_steps);
for(int i = 0; i < N; i++)
{
for(int j = 0; j < N; j+=2)
{
neighbors[i][j] = 0;
neighbors[i][j+1] = 0;
neighbors_2[i][j] = 0;
neighbors_2[i][j+1] = 0;
}
}
if((output == 2) && (status == 1)){
printf("Step %d:\n", t);
print_world(one_step);
printf("Step %d:\n", t+1);
print_world(two_steps);
}
// Save previous step
update(old, world);
//t+=1;
t+=2;
}
//printf("It took %d steps to reach the final state\n", t-2);
printf("It took %d steps to reach the final state\n", (t-3));
if(output==1 || output ==2){
printf("Final state:\n");
print_world(world);
}
for (int i = 0; i < (6*n); i++)
{
free(buffer[i]);
}
free(buffer);
}
void * thread_func(void *arg)
{
pthread_mutex_lock(&lock);
t_info *threadinfo = arg;
int threadID = threadinfo->threadID;
int low = threadinfo->low;
int high = threadinfo->high;
//int **world = threadinfo->world;
//int **neighbors = threadinfo->neighbors;
int i; //rows
int j; //col
for (i = low; i <= high; i++){
for (j = 0; j <= N-1; j++){
if (i > 0){
if (j > 0){
if (threadinfo->world[i-1][j-1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (j < N-1){
if (threadinfo->world[i-1][j+1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (threadinfo->world[i-1][j] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (i < N-1){
if (j > 0){
if (threadinfo->world[i+1][j-1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (j < N-1){
if (threadinfo->world[i+1][j+1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (threadinfo->world[i+1][j] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (j > 0){
if (threadinfo->world[i][j-1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if(j < N-1){
if (threadinfo->world[i][j+1] == 1)
threadinfo->neighbors[i][j] +=1;
}
}
}
pthread_mutex_unlock(&lock);
pthread_exit(NULL);
}
void print_world(int **world)
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j+=2)
{
printf("%d ", world[i][j]);
printf("%d ", world[i][j+1]);
}
printf("\n");
}
printf("\n");
}
void count_neighbors(int **world, int **neighbors)
{
int i; //rows
int j; //col
for (i = 0; i <= N-1; i++){
for (j = 0; j <= N-1; j++){
if (i > 0){
if (j > 0){
if (world[i-1][j-1] == 1)
neighbors[i][j] +=1;
}
if (j < N-1){
if (world[i-1][j+1] == 1)
neighbors[i][j] +=1;
}
if (world[i-1][j] == 1)
neighbors[i][j] +=1;
}
if (i < N-1){
if (j > 0){
if (world[i+1][j-1] == 1)
neighbors[i][j] +=1;
}
if (j < N-1){
if (world[i+1][j+1] == 1)
neighbors[i][j] +=1;
}
if (world[i+1][j] == 1)
neighbors[i][j] +=1;
}
if (j > 0){
if (world[i][j-1] == 1)
neighbors[i][j] +=1;
}
if(j < N-1){
if (world[i][j+1] == 1)
neighbors[i][j] +=1;
}
}
}
}
void next_step(int **world, int **one_step, int **neighbors)
{
int i, j;
for (i = 0; i < N; i++){
for (j = 0; j < N; j++){
if (world[i][j] == 1)
{
if (neighbors[i][j] == 2 || neighbors[i][j] == 3)
one_step[i][j] = 1;
else
one_step[i][j] = 0;
}
else if (world[i][j] == 0)
{
if (neighbors[i][j] == 3)
one_step[i][j] = 1;
else
one_step[i][j] = 0;
}
}
}
}
void update(int **world, int **one_step)
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j+=2)
{
world[i][j] = one_step[i][j];
world[i][j+1] = one_step[i][j+1];
}
}
}
int compare(int **world, int **one_step, int **two_steps, int **old, int status)
{
int counter1=0, counter2=0, counter3=0;
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if(world[i][j] == one_step[i][j])
counter1++;
if(world[i][j] == 0)
counter2++;
if(old[i][j] == two_steps[i][j])
counter3++;
}
}
if (counter1 == (N*N))
status = 0;
else if(counter2 == (N*N))
status = 0;
else if(counter3 == (N*N))
status = 0;
return status;
}
When I compile the code and run it using 2, 4 and 8 threads I get the following:
gcc -o gol gol.c -lpthread
time ./gol 500 1 0 2
It took 1670 steps to reach the final state
real 0m10.064s
user 0m8.971s
sys 0m0.246s
time ./gol 500 1 0 4
It took 1670 steps to reach the final state
real 0m15.694s
user 0m9.976s
sys 0m0.437s
time ./gol 500 1 0 8
It took 1670 steps to reach the final state
real 0m14.600s
user 0m10.400s
sys 0m0.855s
Also the %CPU using top is ~65% when using 2 threads, ~78% when using 4 threads and ~100% when using 8 threads. What am I doing wrong?
You've got 2 problems:
a) Creating threads and waiting for them to terminate adds overhead. Doing it inside a "while(status == 1)" loop means that you're paying for that extra overhead repeatedly. It'd be better to create the threads once (outside the loop) then re-use the existing threads, using something (e.g. condition variable) to make the threads wait for the next iteration of the loop.
b) Mutexes exist to prevent (unwanted) parallelism, and also have overhead. If the threads acquire a mutex, then do their work, then release a mutex; then you're deliberately preventing all parallelism between these threads. For your code, parallelism between the main thread and the newly created threads is also prevented (main thread sits waiting in a pthread_join()).
Essentially; you've added lots of overhead (creating and destroying threads, acquiring and releasing mutexes) and prevented all parallelism to ensure that there's no benefits to outweigh the extra overhead; leading to code that is worse than not using threads at all.
To fix this you need to find ways to ensure that threads can do useful work in parallel. The easiest way to do that would probably be to use 2 global arrays to represent the state of the world, where one of these arrays is "previous world state" and the other is "next world state", and where you swap (pointers to) the arrays between steps. In this case, during a step, "previous world state" is only being read (and many threads can read in parallel without a problem) and each thread can update different parts of "next world state" in parallel. Note that because the threads would write to each cell in "next world state" you won't need to clear "next world state" between steps either.
WARNING: To ensure that updating one element of the array won't cause "lack of atomicity" problems with other/adjacent elements in the array; you will need to either use an atomic type (sig_atomic_t, C11 I think) with a 2D array, or use "1D array of pointers to 1D arrays" (where each row can only be modified by one thread) and the element/s are volatile. Note that if the world state is an 8 * 8 grid you can probably represent a whole row with a single uint8_t (meaning that it could become "1D array of pointers to volatile uint8_t).
Basically (if you include the re-use of threads) it can be done without using any mutexes for anything other than worker threads waiting for the main thread to start the next step, and the main thread waiting for worker threads to complete the current step.
Also; instead of waiting for worker threads, the main thread can also participate in doing useful work. For example, if the world state is an 8 * 8 grid, then "main thread + 7 worker threads" can do a row each (in parallel) to ensure that all 8 rows are done. However, when threads have the same priority it's rarely sane to have more threads than CPUs; so it can be a good idea to check how many CPUs the computer has and limit the number of threads (e.g. if there are 4 CPUs, then you might have "main thread + 3 more threads do 2 rows each").
Let a row of 8000 lamps. Initially, only the one located to the left is lit.
Then, every second, the following operation is performed: each lamp changes state (on or off) if the one on its left was lit a second before. The leftmost lamp stays on all the time. This operation is instantaneous.
The process stops when the lamp at the right end lights for the first time.
How many lights are on?
My following implementation of the problem is false, can you help me?
#include <cstdio>
int t[8001][2];
int main()
{
t[1][0] = 1;
t[1][1] = 1;
int cpt1 = 0, ip = 0;
while (t[8000][0] != 1 && t[8000][1] != 1)
{
ip++;
for (int j=2;j<8001;j++)
{
if(t[j-1][!(ip&1)])
t[j][(ip & 1)] = !t[j][!(ip & 1)];
}
}
for(int j = 1;j < 8001; j++)
cpt1 += t[j][1];
printf("cpt=%d\n", cpt1);
}
Code is missing an update when the left does not change.
Code simplified (zero based offset, use of bool) and corrected below
#include<stdbool.h>
#include<stdio.h>
#define N 8000
bool t[N][2];
int main(void) {
t[0][0] = true;
t[0][1] = true;
int ip = 0;
while (t[N - 1][0] == 0 && t[N - 1][1] == 0) {
ip = !ip;
for (int j = 1; j < N; j++) {
if (t[j - 1][!ip]) {
t[j][ip] = !t[j][!ip];
} else {
t[j][ip] = t[j][!ip]; // add
}
}
}
int cpt1 = 0;
for (int j = 0; j < N; j++) {
cpt1 += t[j][1];
}
printf("N=%d cpt=%d\n", N, cpt1);
return 0;
}
Output
N=8000 cpt=2048
the following proposed code:
cleanly compiles
uses C header files rather than C++ header files
performs the desired operation, but not the fastest possible algorithm
is liberally commented
And now the proposed code:
#include <stdio.h>
int t1[8000]; // initially all zeros
int t2[8000];
int main( void )
{
// setup initial conditions
int numLitLights = 0;
t1[0] = 1;
// while stop condition not true
while ( t1[7999] != 1 )
{
// make one pass through lamps
// update values
for (int j=0; j<7999; j++)
{
if( t1[j] )
{
t2[j+1] = ( t1[j+1] )? 0 : 1;
}
}
// update original
for( int j=0; j< 8000; j++ )
{
t1[j] = t2[j];
}
}
// count lit lamps
for(int j = 0; j < 8000; j++)
{
if( t1[j] )
{
numLitLights++;
}
}
// output number of lit lamps
printf( "number of lit lamps: %d\n", numLitLights );
} // end function: main
The result (number of lamps lit) is
1024
int run_me(unsigned long prime, unsigned long max, int *ary) {
unsigned long i;
printf("\nI am %d", prime);
if(prime > sqrt(max)) {
return 1; /* do no run */
}
for(i = 3; i*prime < max; i+=2) {
ary[i*prime - 1] = 1;
}
return 0;
}
typedef struct Args {
unsigned long max, prime;
int *ary;
} args;
void *thread_runner(void *all_args) {
args *my_args = all_args;
run_me(my_args->prime, my_args->max, my_args->ary);
return 0;
}
unsigned long *sieve_of_eratosthenes(unsigned long begin, unsigned long end) {
unsigned long i, j, arylen, *ary_to_ret;
unsigned long current_primes[4] = {3, 5, 7, 11}; /* holds primes being used by threads*/
int *ary_of_all;
pthread_t threads[4];
args *curr;
curr = malloc(sizeof(args));
ary_of_all = calloc(end, sizeof(int));
arylen = end - begin + 2;
ary_to_ret = calloc(arylen, sizeof(unsigned long));
ary_of_all[0] = 1;
/*mark all even numbers*/
for(i = 1; 2 * i < end; i++) {
ary_of_all[2*i - 1] = 1;
}
while(current_primes[3] < sqrt(end)) {
/*run threads with current primes*/
for(i = 0; i < 4; i++) {
curr->prime = current_primes[i];
curr->max = end;
curr->ary = ary_of_all;
pthread_create(&threads[i], NULL, thread_runner, curr);
}
/* join all threads */
for(i = 0; i < 4; i++) {
pthread_join(threads[i], NULL);
}
j = 0; /* number of primes found */
/*find new primes*/
for(i = current_primes[3] + 2; i < end && j < 4; i+=2) {
if(ary_of_all[i - 1] == 0) {
current_primes[j] = i;
j++;
}
}
}
/*run threads one more time*/
if(current_primes[0] <= sqrt(end)) {
for(i = 0; i < 4; i++) {
curr->prime = current_primes[i];
curr->max = end;
curr->ary = ary_of_all;
pthread_create(&threads[i], NULL, thread_runner, curr);
}
/* join all threads */
for(i = 0; i < 4; i++) {
pthread_join(threads[i], NULL);
}
}
/*create the array to be returned*/
j = 0; /*pos in *ary_to_ret*/
for(i = begin; i <= end; i++) {
if(ary_of_all[i-1] == 0) {
ary_to_ret[j] = i;
j++;
}
}
ary_to_ret[j] = 0; /* null terminate */
ary_to_ret = realloc(ary_to_ret, (j+1) * sizeof(unsigned long));
return ary_to_ret;
}
I am running the above code in order to get a list of primes given a high and low value using the Sieve of Eratosthenes. I have the code mostly working, however when I run this code the thread which I create using the first element in my curr_primes array is never used and instead runs 5, 7, 11, 11. It does this every time it runs through the array and repopulates it. I was wondering if someone could explain to me why it runs in this way.
You are passing the same curr pointer to all the threads. You are lucky that it even works as well as you have observed as that is a huge race condition. Instead, the code needs to pass a seperate arg buffer to each thread. Here is one example:
/* doesn't really need to be dynamic memory in this simple example */
args curr[4];
for(i = 0; i < 4; i++) {
curr[i].prime = current_primes[i];
curr[i].max = end;
curr[i].ary = ary_of_all;
pthread_create(&threads[i], NULL, thread_runner, &curr[i]);
}
/* join all threads */
for(i = 0; i < 4; i++) {
pthread_join(threads[i], NULL);
}
I am relatively new to C and I am trying to get my Bankers Algorithm to work below. The logic is solid, but I am getting compilation errors that I can't quite work out. The main one is dealing with my struct that holds all of the consumers data for the algorithm. It reads:
"error: invalid type argument of ‘->’ (have ‘struct threadData’)
t->allocation[t->customer_num][i] = t->allocation[t->customer_num][i] - t->requestOrRelease[i];"
That is one of many similar errors.
I know you may find more, since I am not done yet, so if you do, shout them out.
I have been working on this forever and I am stuck. Any help would be awesome. Keep in mind, I know there are things I may not be doing the best possible, but I want my code below to work and then I will optimize.
I know the code is lengthy, but I greatly appreciate any help. Thank you!
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <stdbool.h>
#define cust 5
#define reso 3
struct threadData
{
int available[reso];
int maximum[cust][reso];
int allocation[cust][reso];
int need[cust][reso];
int requestOrRelease[reso];
int customer_num;
} ;
void request_resources(struct threadData *t);
void release_resources(struct threadData *t);
int isSafeState(int work[],int need[][cust],int allocation[][cust]);
int sumVector(int input[]);
int sumRowCol(int input[][cust],int index,char c);
void fillRequestRelease(int * array,int max0,int max1,int max2);
int main(int argc, const char **argv)
{
int available[reso]; //number of resources available of each type
int maximum[cust][reso]; //maximum demand of each process
int allocation[cust][reso]; //number of resources of each type currently allocated
int need[cust][reso]; //remaining resouce needs of each process : maximum-allocation
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL); //Create mutex lock
bool end = false;
//===========================================
srand(time(NULL));
int i,j,r;
for(i = 0;i < argc;i++) //Initialize values in available array
{
r = atoi(argv[i]);
available[i] = r;
}
for(i = 0;i < cust;i++) //Initialize values in maximum array
{
for(j = 0;j < reso;j++)
{
r = rand()%8; //Random int between 0 and 7
reso[i][j] = r;
}
}
for(i = 0;i < cust;i++) //Initialize values in allocation/need arrays
{
for(j = 0;j < reso;j++)
{
allocation[i][j] = 0;
need[i][j] = 0;
}
}
//===========================================
threadData data;
data.available = available;
data.maximum = maximum;
data.allocation = allocation;
data.need = need;
data.requestOrRelease = requestOrRelease;
data.customer_num = 0;
pthread_t custRequest0,custRequest1,custRequest2,custRequest3,custRequest4;
pthread_t custRelease0,custRelease1,custRelease2,custRelease3,custRelease4;
while(true)
{
data.customer_num = 0;
fillRequestRelease(data.requestOrRelease,data.need[0][0],data.need[0][1],data.need[0][2]);
pthread_create(&custRequest0,NULL,(void *)data);
data.customer_num = 1;
fillRequestRelease(data.requestOrRelease,data.need[1][0],data.need[1][1],data.need[1][2]);
pthread_create(&custRequest1,NULL,(void *)data);
data.customer_num = 2;
fillRequestRelease(data.requestOrRelease,data.need[2][0],data.need[2][1],data.need[2][2]);
pthread_create(&custRequest2,NULL,(void *)data);
data.customer_num = 3;
fillRequestRelease(data.requestOrRelease,data.need[3][0],data.need[3][1],data.need[3][2]);
pthread_create(&custRequest3,NULL,(void *)data);
data.customer_num = 4;
fillRequestRelease(data.requestOrRelease,data.need[4][0],data.need[4][1],data.need[4][2]);
pthread_create(&custRequest4,NULL,(void *)data);
pthread_join(custRequest0,NULL);
pthread_join(custRequest1,NULL);
pthread_join(custRequest2,NULL);
pthread_join(custRequest3,NULL);
pthread_join(custRequest4,NULL);
data.customer_num = 0;
fillRequestRelease(data.requestOrRelease,data.allocation[0][0],data.allocation[0][1],data.allocation[0][2]);
pthread_create(&custRelease0,NULL,(void *)data);
data.customer_num = 1;
fillRequestRelease(data.requestOrRelease,data.allocation[1][0],data.allocation[1][1],data.allocation[1][2]);
pthread_create(&custRelease1,NULL,(void *)data);
data.customer_num = 2;
fillRequestRelease(data.requestOrRelease,data.allocation[2][0],data.need[2][1],data.need[2][2]);
pthread_create(&custRelease2,NULL,(void *)data);
data.customer_num = 3;
fillRequestRelease(data.requestOrRelease,data.allocation[3][0],data.allocation[3][1],data.allocation[3][2]);
pthread_create(&custRelease3,NULL,(void *)data);
data.customer_num = 4;
fillRequestRelease(data.requestOrRelease,data.allocation[4][0],data.allocation[4][1],data.allocation[4][2]);
pthread_create(&custRelease4,NULL,(void *)data);
pthread_join(custRelease0,NULL);
pthread_join(custRelease1,NULL);
pthread_join(custRelease2,NULL);
pthread_join(custRelease3,NULL);
pthread_join(custRelease4,NULL);
int nonZeroCount = 0;
for(i = 0;i < cust;i++)
{
for(j = 0;j < reso;j++)
{
if(need[i][j] > 0)
nonZeroCount++;
}
}
if(nonZeroCount == 0)
break;
}
printf("Program done!")
}
//Determines if system is in safe state
//Returns 0 if in safe state, else -1
int isSafeState(int work[],int need[][cust],int allocation[][cust]) //work = available
{
int i,j;
int temp1,temp2,trueCount,notSafeCount;
bool finish[sizeof(need)/sizeof(int)];
for (i = 0;i < sizeof(need)/sizeof(int);i++)
finish[i] = false;
trueCount = 0;
bool iexists = false;
while(true)
{
for(i = 0;i < sizeof(finish)/sizeof(int);i++)
{
temp1 = sumRowCol(need,i,'r');
temp2 = sumRowCol(work,0,'r');
if(finish[i] == false && (temp1 <= temp2))
{
finish[i] = true;
for(j = 0;j < reso;j++)
work[j] = work[j] + allocation[i][j];
trueCount++;
iexists = true;
}
}
if(trueCount == sizeof(finish)/sizeof(int))
return 0;
else if(iexists == false)
return -1;
}
}
// Returns sum of given vector
int sumVector(int input[])
{
int sum = 0;
int i;
for(i = 0;i < sizeof(input)/sizeof(int);i++)
sum += input[i];
return sum;
}
//Returns sum of given input array row/column
int sumRowCol(int input[][cust],int index,char c)
{
int sum = 0;
int i;
if(c == 'r')
{
for(i = 0;i < sizeof(input)/sizeof(int);i++)
sum += input[index][i];
}
else
{
for(i = 0;i < sizeof(input)/sizeof(int);i++)
sum += input[i][index];=
}
return sum;
}
void request_resources(struct threadData t)
{
int i,j,safeState,custNum;
int tempAvailable[reso];
int tempMaximum[cust][reso];
int tempAllocation[cust][reso];
int tempNeed[cust][reso];
int tempRequest[reso];
bool end = false;
if(t->requestOrRelease[0] == 0 && t->requestOrRelease[1] == 0 && t->requestOrRelease[2] == 0)
return;
while(true)
{
custNum = t->customer_num;
for(int i = 0;i < reso;i++)
{
if(t->requestOrRelease[i] > t->need[custNum][i])
{
printf("Error: Request is greater than need. Aborting request to bank.");
pthread_mutex_unlock(&mutex);
return;
}
}
int passCount;
while(true)
{
passCount = 0;
for(int i = 0;i < reso;i++)
{
if(t->requestOrRelease[i] > t->available[i])
{
passCount--;
while(true)
{
if(t->requestOrRelease[i] <= t->available[i])
break;
}
}
passCount++;
}
if(passCount = reso)
break;
}
pthread_mutex_lock(&mutex); //get mutex lock
//Filling temporary arrays with current data
//===========================================
for(i = 0;i < cust;i++)
{
for(j = 0;j < reso;j++)
{
tempMaximum[i][j] = t->maximum[i][j];
tempAllocation[i][j] = t->allocation[i][j];
tempNeed[i][j] = t->need[i][j];
}
tempAvailable[i] = t->available[i];
tempRequest[i] = t->requestOrRelease[i];
}
//===========================================
//"Pretend" to allocate resources
for(i = 0;i < reso;i++)
{
tempAvailable[i] = tempAvailable[i] - tempRequest[i];
tempAllocation[custNum][i] = tempAllocation[custNum][i] + tempRequest[i];
tempNeed[custNum][i] = tempNeed[custNum][i] - tempRequest[i];
}
safeState = isSafeState(tempAvailable,tempNeed,tempAllocation);
if(safeState == 0)
{
for(i = 0;i < reso;i++)
{
t->available[i] = t->available[i] - tempRequest[i];
t->allocation[custNum][i] = t->allocation[custNum][i] + tempRequest[i];
t->need[custNum][i] = t->need[custNum][i] - tempRequest[i];
}
pthread_mutex_unlock(&mutex); //release mutex lock
end = true;
}
if(end == true)
break;
pthread_mutex_unlock(&mutex); //release mutex lock
}
printf("Request resources granted to consumer: %d",custNum);
}
void release_resources(struct threadData t)
{
int i;
pthread_mutex_lock(&mutex); //get mutex lock
for(i = 0;i < reso;i++)
{
t->available[i] = t->available[i] + t->requestOrRelease[i];
t->allocation[t->customer_num][i] = t->allocation[t->customer_num][i] - t->requestOrRelease[i];
}
pthread_mutex_unlock(&mutex); //release mutex lock
}
//Generates random integers for request and release vectors
void fillRequestRelease(int * array,int max0,int max1,int max2)
{
srand(time(NULL));
int r;
r = rand()%(max0+1);
array[0] = r;
r = rand()%(max1+1);
array[1] = r;
r = rand()%(max2+1);
array[2] = r;
}
As far as I can see, in your request_resources() function, t is not a pointer variable. So, instead of
t->requestOrRelease[0]
you should be using
t.requestOrRelease[0]
and so on.
t is not a pointer, so you must write t.field instead of t->field.
The important clue in the error message is "(have ‘struct threadData’)".
This means you are using the pointer dereference operator -> on a struct, instead of on a struct pointer. Use the member dereference operator . instead.
The program triggers a break point on the free() function call.
Debugging the program returns this message:
HEAP[C_C.exe]: Heap block at 00498240 modified at 00498298 past requested size of 50
C_C.exe has triggered a breakpoint.
I don't understand why free() triggers the break point if all seems correct...
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
int* aloca_vetor(int control)
{
int *vetor;
vetor = (int *)malloc((control * sizeof(int)));
return vetor;
}
int main()
{
int *vetor;
int Input[2];
int testes;
int control;
int i, j, w = 0;
scanf("%d", &testes);
while (testes != 0)
{
scanf("%d%d", &Input[0], &Input[1]);
control = ((Input[1] - Input[0]) + 2);
vetor = aloca_vetor(control);
if (vetor == NULL)
{
printf("No memory!");
}
for (i = 2; i < control; i++)
{
vetor[i] = TRUE;
}
for (i = 2; i < control; i++)
{
if (vetor[i] == TRUE)
{
j = 0;
for (w = 0; j < (control - 1); w++)
{
j = i*i + w*i;
vetor[j] = FALSE;
}
}
}
for (i = 0; i < control; i++)
{
if (vetor[i] == TRUE)
{
printf("%d\n", i);
}
}
testes--;
free(vetor);
}
return 0;
}
I think that the problem arises in this loop
for (w = 0; j < (control - 1); w++)
{
j = i*i + w*i;
vetor[j] = FALSE;
}
It seems that the value calculated such a way as
j = i*i + w*i;
can be greater than control.
You could rewrite the loop like
for (w = 0; ( j = i*i + w*i ) < (control - 1); w++)
{
vetor[j] = FALSE;
}
Also in my opinion the loop
while (testes != 0)
{
//...
testes--;
free(vetor);
}
would be more readable if it would be rewritten the following way
while ( testes-- != 0 )
{
//...
free(vetor);
}
or
while ( testes-- )
{
//...
free(vetor);
}
Take into account that you wrote the program such a way that it seems nobody understands what it does.:) You should try to write programs more readable even if they are test programs.
j = i*i + w*i will become much larger than the last valid index for the array. Accesses beyond the borders of an array presents undefined behaviour.
One effect might be to overwrite memory used by the hep management, so the effect will only become visible when calling free.