I have an assignment in C Language; the requirement is that I am given number of students, everyone has 2 grades midterm grade and final grade my task is to calculate the number of students who passed. But I will use forking; we will fork Teaching Assistants to separately choose whether a student should pass or not and the number of Teaching Assistants will be passed on terminal.
Everything is fine. I wrote the code, but I noticed something very weird, I got a segmentation fault which is so weird because I am sure I am not accessing wrong memory. I tried to print something (line 53) and I found that this line is printed 4 times actually, which is equal to number of children + parent, although this line above the fork(). My code creates more than one process (TA) and every TA takes a partition and calculate number of passed students and exit with this code and on parent I make for loop and wait until any child dies so I print its exit code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
void main(int argc, char **argv)
{
int Number_of_TAs = atoi(argv[1]);
int leastgrade = atoi(argv[2]);
int size_of_array = 0;
int flag = 0;
int last_visited = 0;
int ind = 0;
FILE* ptr;
char ch;
// Opening file in reading mode
ptr = fopen("students.txt", "r");
if (NULL == ptr) {
printf("file can't be opened \n");
}
do {
ch = fgetc(ptr);
size_of_array = 2 * ((int)ch - 48);
break;
} while (ch != EOF);
fclose(ptr);
int arr_of_grades[size_of_array];
int arr_of_grades2[size_of_array/2];
FILE *myFile;
myFile = fopen("students.txt", "r");
int *dummy;
fscanf(myFile, "%d", &dummy);
for (int i = 0; i < size_of_array; i++)
fscanf(myFile, "%d", &arr_of_grades[i]);
int index2 = 0;
printf("%d", size_of_array);
printf(" ");
for (int i = 0; i< size_of_array; i=i+2)
{
arr_of_grades2[index2] = arr_of_grades[i] + arr_of_grades[i+1];
index2 = index2 + 1;
}
fclose(myFile);
int pid, stat_loc;
int passed_students = 0;
int partion = size_of_array / (2 * Number_of_TAs );
for (int i=0; i< Number_of_TAs; i++)
{
pid = fork();
ind = ind + partion;
}
if (pid == 0)
{
for (int i = ind; i< ind + partion; i++)
{
if (arr_of_grades2[i]>=leastgrade )
passed_students = passed_students + 1;
}
exit(passed_students);
}
else
{
int sid;
for (int i = 0; i<Number_of_TAs; i++)
{
sid = wait(&stat_loc);
if(!(stat_loc & 0x00FF))
printf(stat_loc>>8);
printf(" ");
}
}
return 0;
}
I am a newbie in C so I didn't try many things
The segmentation fault issue may happen at any array access with the wrong index.
In your case, it may happen at the first 2 lines:
int Number_of_TAs = atoi(argv[1]);
int leastgrade = atoi(argv[2]);
if you execute the program without the 2 parameters.
Another issue of your program is that you should move the if-else statement where you check the pid inside the for loop where you create the processes with the fork() otherwise it creates more processes than expected.
Related
I'm trying to make a multi-threaded prime numbers counter program. I've added the critical codes for the understanding (the parseargs function works great in another program and feels unnecessary and I don't want to overload you with code).
Long story short, the program compile and work well with small numbers (up to 1000 max val and 8 threads), but when I'm trying to go with bigger numbers I keep getting a lot of errors like:
segmentation fault: core dumped, Floating point exception, realloc(): invalid next size.
What's wrong with the code? I know that I should use fewer global variables but I'm trying to make it work and then I will make cleaner and better.
And the only place that I'm using realloc is inside of isprime; that works great in my other programs. What's the problem there?
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
void parseargs(char *argv[], int argc, int *lval, int *uval, int *nval, int *tval);
int isprime(int n);
void setFlags();
pthread_mutex_t num_lock;
pthread_mutex_t count_lock;
char *flagarr = NULL;
int num;
int lval = 1;//min value
int uval = 100;//max value
int count = 0;//primes counter
int main (int argc, char **argv)
{
int nval = 10;// how much numbers to print
int tval = 4;// threads number
num = lval;
if (pthread_mutex_init(&num_lock, NULL) != 0) {
printf("\n mutex init has failed\n");
return 1;
}
if (pthread_mutex_init(&count_lock, NULL) != 0) {
printf("\n mutex init has failed\n");
return 1;
}
// Parse arguments
parseargs(argv, argc, &lval, &uval, &nval, &tval);// works 100% (change the defult starting vals)
if (uval < lval)
{
fprintf(stderr, "Upper bound should not be smaller then lower bound\n");
exit(1);
}
if (lval < 2)
{
lval = 2;
uval = (uval > 1) ? uval : 1;
}
if (tval<1)
tval=4;
// Allocate flags
flagarr= (char *)malloc(sizeof(char) * (uval-lval+1));
if (flagarr == NULL)
exit(1);
//Allocate threads
pthread_t* t = (pthread_t *)malloc(sizeof(pthread_t)*tval);
if (t == NULL)
exit(1);
//start threads
for(int i =0; i<tval ; i++){
printf("%d\n",i);
pthread_create(&t[i],NULL,(void*)setFlags,NULL);
}
for(int i =0; i<tval ; i++)
pthread_join(t[i],NULL);
// Print results
nval=count;
printf("Found %d primes from %d to %d%c", count, lval,uval , count ? ' ' : '.');
if(count && nval>0)
printf("and printing the first %d of them:\n",nval);
else
printf("\n");
for (num = lval; (num <= uval) && (nval) ; num++)
if (flagarr[num - lval])
{
nval--;
count--;
printf("%d%c", num, (count && nval) ? ',' : '\n');
}
free(flagarr);
free(t);
return 0;
}
void setFlags()
{
int myNum;
for (; num <= uval;)
{
pthread_mutex_lock(&num_lock);
myNum=num;
num++;
pthread_mutex_unlock(&num_lock);
if (isprime(myNum))
{
flagarr[myNum - lval] = 1;
pthread_mutex_lock(&count_lock);
count ++;
pthread_mutex_unlock(&count_lock);
} else {
flagarr[myNum - lval] = 0;
}
}
}
int isprime(int n)
{
static int *primes = NULL; // NOTE: static !
static int size = 0; // NOTE: static !
static int maxprime; // NOTE: static !
int root;
int i;
// Init primes array (executed on first call)
pthread_mutex_lock(&first_lock);
if (primes == NULL)
{
primes = (int *)malloc(2*sizeof(int));
if (primes == NULL)
exit(1);
size = 2;
primes[0] = 2;
primes[1] = 3;
maxprime = 3;
}
pthread_mutex_unlock(&first_lock);
root = (int)(sqrt(n));
// Update primes array, if needed
while (root > maxprime)
for (i = maxprime + 2 ; ; i+=2)
if (isprime(i))
{
pthread_mutex_lock(&primeFunc_lock);
size++;
primes = (int *)realloc(primes, size * sizeof(int));
if (primes == NULL)
exit(1);
primes[size-1] = i;
maxprime = i;
pthread_mutex_unlock(&primeFunc_lock);
break;
}
// Check 'special' cases
if (n <= 0)
return -1;
if (n == 1)
return 0;
// Check prime
for (i = 0 ; ((i < size) && (root >= primes[i])) ; i++)
if ((n % primes[i]) == 0)
return 0;
return 1;
}
I know that I should use fewer global variables but I'm trying to make it work and then I will make cleaner and better.
For multithreaded programs this approach doesn't work -- you can't write a buggy program first, and make it pretty and bug-free later -- you have to get it bug-free first.
Also, global and static variables and threads generally don't mix.
Now, as others have noted, you access static variables in isprime() without any locks. Think about what would happen when thread T1 executes this code:
for (i = 0 ; ((i < size) && (root >= primes[i])) ; i++)
if ((n % primes[i]) == 0)
and another thread T2 executes this statement at the same time:
primes = (int *)realloc(primes, size * sizeof(int));
Since primes is not an atomic variable, the compiler will (likely) load the value of primes into some register, and continue using that value through the entire loop in T1. The loop will be totally oblivious to the fact that primes may have already been free()d and realloc()ed in T2, and now points to entirely different memory block. T1 will continue reading the old (now dangling) memory.
Similar problems exist throughout your isprimes() function, and easily explain your observed crashes.
If you are on a Linux system, Thread sanitizer (and Address sanitizer) are your friends.
I am a beginner so if I miss something vital to the code please forgive me haha. I am making a program which gets input from the console that says how many characters are going to be used, the characters (single letters), and then how long you want the password to be. I feel like I am pretty close, but every time I run the program, it seems to generate a random pattern of letters and I can't follow it.
Here is my code, including the main function.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 100
int generatePassword(char* characters[], int i, char s[], int numCharacters, int passwordLength) {
if (i==0) {
printf("%s\n", s);
return 0;
}
for (int j = 0; j < passwordLength; j++) {
strcat(s, characters[j]);
generatePassword(characters, i-1, s, numCharacters, passwordLength);
}
return 0;
}
void homeFunction(char* characters[], int numCharacters, int passwordLength) {
for (int i = 1; i <= numCharacters; i++) {
char s[MAX] = "";
int c = generatePassword(characters, i, s, numCharacters, passwordLength);
}
}
int main (int argc, char *argv[]) {
if (argc < 2) {
printf("ERROR: Program did not execute due to lack of arguments.\n");
return -1;
}
int numCharacters;
numCharacters = atoi(argv[1]);
int passwordLength;
passwordLength = atoi(argv[numCharacters+2]);
for (int i = 0; i < numCharacters; i++) {
if (strlen(argv[i+1]) > 1) {
printf("ERROR: You can only input one character at a time.\n");
return -1;
}
}
if (argv != numCharacters + 3) {
printf("ERROR: Invalid number of arguments.\n");
return -1;
}
char *charArray[numCharacters];
charArray[numCharacters] = (char*)malloc(numCharacters * sizeof(char));
for (int i = 0; i < numCharacters; i++) {
charArray[i] = argv[i+2];
}
homeFunction(charArray, numCharacters, passwordLength);
return 0;
}
In theory, if the user ran the program with "./NAME 2 a b 2" the result should be
a
b
aa
ab
ba
bb
This is my current output. How can I make it look like the output above?
a
ab
abaa
abaab
abaabba
abaabbab
You need to learn the fundamentals of arrays and strings.
Imagine if I run your code as app.exe 99
This is undefined behavior:
numCharacters = atoi(argv[1]);
int passwordLength;
passwordLength = atoi(argv[numCharacters+2]);
If argv[1] is say, "99", then numCharacters will be 99.
Then passwordLength will be assigned the atoi conversion of argv[101]. But there's only two valid elements in argv: argv[0], which is the executable path, and argv[1], which is "99". argv[2] and up is random memory that's not yours to look at.
This is also wrong:
char *charArray[numCharacters];
charArray[numCharacters] = (char*)malloc(MAX * sizeof(char));
You are allocating an array of (string) pointers, then assigning to an index one past the valid range of the array.
I was trying to write a function that could copy a text file content line by line to a matrix, so this is what I came up with:
#include <stdio.h>
#include <stdlib.h>
#define rows 5
#define columns 12
void file_to_matrix(char *matrix[]){
FILE *file = fopen("swamp.txt", "r");
if(file==NULL){
printf("File error");
exit(1);
}
int y=0;
for(int x=0; (matrix[y][x]=fgetc(file))!=EOF; ++x){
if(matrix[y][x]=='\n'){
++y;
x=0;
}
}
fclose(file);
}
int main(){
char *matrix[rows];
file_to_matrix(matrix);
for(int i=0; i<5; ++i){
for(int j = 0; j < 11; j++){
printf("%c", matrix[i][j]);
}
printf("\n");
}
}
I tried to compile and run it on Windows and Linux but the only thing that it manages to do is giving me errors that are practically useless like:
"Stopping due to fatal error: NullReferenceException: Object reference not set to an instance of an object"
or
"Segmentation fault (core dumped)"
You have to allocate memory for each element of matrix. This is the same exact mistake as writing:
char *s = "string";
As the first act of the program, loop through matrix, and call malloc for each cell:
int i;
for (i = 0; i < 5; ++i)
if (!(matrix[i] = malloc(MAXLEN))) [
perror("malloc");
exit(EXIT_FAILURE);
}
Note: we check the return value of malloc to ensure no errors have occurred.
with your code, i think the matrix in the file will restricted (you define rows=5 and columns=12). so i think again to write a code that can be flexible, no need to set max row or column again. here we go
#include <stdio.h>
#include <stdlib.h> //malloc realloc
//file read function. returning string with splitted new line
//ex: (note: newline is '\n' (ENTER))
//test.txt:
//10 20 30(space)(newline)
//40 50 60(space)(newline)
void file_to_matrix(char *filename)
{
FILE * file = fopen(filename, "r");
char *buff = (char*)malloc(sizeof(char)); //temp string
int *matrix_row = (int*)malloc(sizeof(int)); //temp matrix row
int **MATRIX = (int**)malloc(sizeof(int*)); //this will become the final matrix
int index_buff = 0, index_MATRIX = 0, index_matrix_row = 0;
while (1)
{
char c = getc(file);
if (c==EOF)
{
break;
}
if (c=='\n') //if c meet newline, then add the matrix row to final matrix
{
(*(MATRIX+index_MATRIX)) = matrix_row;
index_MATRIX++;
MATRIX = realloc(MATRIX, sizeof(MATRIX)*(index_MATRIX+1));
matrix_row = (int*)malloc(sizeof(int));
index_matrix_row = 0;
printf("\n");
continue;
}
if (c==' ') //if c meet space, then buff wil converted to int
{
int num = atoi(buff);
printf("%d ", num);
(*(matrix_row+index_matrix_row)) = num;
index_matrix_row++;
matrix_row = realloc(matrix_row, sizeof(int)*(index_matrix_row+1));
free(buff);
buff = (char*)malloc(sizeof(char));
index_buff=0;
continue;
}
//add buff with c
(*(buff+index_buff))=c;
index_buff++;
buff = realloc(buff, sizeof(char)*(index_buff+1));
}
fclose(file);
//clearing the dynamic memory
free(buff);
for (int i = 0; i < index_MATRIX; i++)
{
free(MATRIX[i]);
}
}
int main()
{
file_to_matrix("test.txt");
return 0;
}
test.txt:
10 20 30
40 50 60
70 80 90
if you confused with the test.txt format, i will explain again:
10 20 30(space)(newline)
30 40 60(space)(newline)
70 80 90(space)(newline)
Thank you for your replies, I think your solutions are very clever but I was looking to an easier one.
After a little bit of trial and error I think I found a solution that it isn't very generalized but it's simple and it seems to work fine:
#include <stdlib.h>
#include <stdio.h>
#define ROWS <n of rows>
#define COLS <n of columns>
void file_to_matrix(int rows, int cols, char matrix[rows][cols], char file_path[]){
FILE *file = fopen(file_path, "r");
if(file==NULL){
printf("File error");
exit(1);
}
int y=0;
for(int x=0; (matrix[y][x]=getc(file))!=EOF; ++x){
if(matrix[y][x]=='\n'){
matrix[y][x]='\0';
++y;
x=-1;
}
}
fclose(file);
}
int main(){
char matrix[ROWS][COLS+2];
file_to_matrix(ROWS, COLS+2, matrix, "file path");
for(int i=0; i<=ROWS; ++i){
printf("%s\n", matrix[i]);
}
}
Thank you again for your answers
Hello I am taking an intro to C-programming class so I am using very basic codes. Here I am simply trying to get a matrix of the commas out of the main string. However when I try running the program it keeps crashing on me and I don't know what is my problem. I was able to use the fgets function correctly so I think that is working fine still.
CD Data.txt File
Eagles, Hotel California, 1976, Rock, 4
The Fratellis, Costello Music, 2006, Garage Rock, 5
Awolnation, Megalithic Symphony, 2011, Indie Rock, 5
Lindsey Stirling, Lindsey Stirling, 2012, Classical Crossover, 5
Arctic Monkeys, AM, 2013, Indie Rock, 4
Program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define row 1000
#define column 1000
void getCommas(char str[], int commas[])
{
int flag, count, index;
count = 0;
index = 0;
flag = 1;
while(flag = 1)
{
if(str[count] = ',')
{
commas[index] = count;
index = index + 1;
}
count = count + 1;
if(str[count] = '\0')
{
flag = 0;
}
}
}
int main()
{
int i;
char CdInfo[row][column];
int Index[row][column];
FILE *fp;
fp = fopen("CD Data.txt","r");
for(i=0; i<5; i++)
{
fgets(CdInfo[i], sizeof CdInfo, fp);
//printf("%s\n",CdInfo[i]);
}
for (i=0; i<5; i++)
{
getCommas(CdInfo[i], Index[i]);
}
fclose(fp);
return 0;
}
These two variables are too big to be on the stack:
int main()
{
int i;
char CdInfo[row][column]; //<<
int Index[row][column]; //<<
declare them as static or as global variables.
And:
while(flag = 1)
should be
while(flag == 1)
and all
if (str[count] = ...
should be
if(str[count] == ...
You should also think about replacing
while(flag = 1) {
with :
while(flag == 1)
// note:
// the code is not making any use of more than one line of the
// input file at any one time, so
// only the current row actually needs to be defined
// note:
// this code makes no check for max length of each row (1000 char)
// that could/will be a problem when the input line is longer than 1000 character
// to avoid the error of writing an assignment rather than a literal,
// place the literal on the left side,
// then the compiler will notify you of the error
// rather than you having to spend time debugging the code
// trying to find the error
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define row 1000
#define column 1000
//void getCommas(char str[], int commas[])
void getCommas( char * pStr, int * pCommas )
{
//int flag, count, index;
//count = 0;
//index = 0;
//flag = 1;
int flag = 1;
int count = 0;
int index = 0;
//while(flag = 1)
// following while loop could eliminate
// the 'flag' variable and related code by using
// and would be safer because never looking at string termination
// character but once.
// while( '\0' != pStr[count] )
while( 1 == flag )
{
//if(str[count] = ',')
if( ',' == pStr[count] )
{
pCommas[index] = count;
index = index + 1;
}
count = count + 1;
//if(str[count] = '\0')
if( '\0' == pStr[count] )
{ // then found end of string
flag = 0;
}
}
}
char CdInfo[row][column];
int Index[row][column];
int main()
{
int i = 0;
int rowCount = 0;
//char CdInfo[row][column]; // this is a huge item on the stack,
//int Index[row][column]; // this is a huge item on the stack,
//FILE *fp;
FILE *fp = NULL;
fp = fopen("CD Data.txt","r");
// always check the result of calls to io functions
if ( NULL == fp )
{ // then fopen failed
perror( "fopen" );
exit(1);
}
// implied else
// there is no reasonable reason (in the real world)
// to expect the input to be only 5 lines
//for(i=0; i<5; i++)
//{
// fgets(CdInfo[i], sizeof CdInfo, fp);
// //printf("%s\n",CdInfo[i]);
//}
for( i=0; i<row; i++ )
{
// following line checks results of call to I/O function
if( 0 == fgets( CdInfo[i], row, fp ) ) { break; }
// above line exits loop on end of file or I/O error
rowCount++;
}
//for (i=0; i<5; i++)
for( i = 0; i < rowCount; i++ )
{
getCommas(CdInfo[i], Index[i]);
}
fclose(fp);
return 0;
}
My program is reading in files and using thread to compute the highest prime number, when I put a print statement into the getNum() function my numbers are printing out. However, it seems to just lag no matter how many threads I input. Each file has 1 million integers in it. Does anyone see something apparently wrong with my code? Basically the code is giving each thread 1000 integers to check before assigning a new thread. I am still a C noobie and am just learning the ropes of threading. My code is a mess right now because I have been switching things around constantly.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
#include <math.h>
#include <semaphore.h>
//Global variable declaration
char *file1 = "primes1.txt";
char *file2 = "primes2.txt";
char *file3 = "primes3.txt";
char *file4 = "primes4.txt";
char *file5 = "primes5.txt";
char *file6 = "primes6.txt";
char *file7 = "primes7.txt";
char *file8 = "primes8.txt";
char *file9 = "primes9.txt";
char *file10 = "primes10.txt";
char **fn; //file name variable
int numberOfThreads;
int *highestPrime = NULL;
int fileArrayNum = 0;
int loop = 0;
int currentFile = 0;
sem_t semAccess;
sem_t semAssign;
int prime(int n)//check for prime number, return 1 for prime 0 for nonprime
{
int i;
for(i = 2; i <= sqrt(n); i++)
if(n % i == 0)
return(0);
return(1);
}
int getNum(FILE* file)
{
int number;
char* tempS = malloc(20 *sizeof(char));
fgets(tempS, 20, file);
tempS[strlen(tempS)-1] = '\0';
number = atoi(tempS);
free(tempS);//free memory for later call
return(number);
}
void* findPrimality(void *threadnum) //main thread function to find primes
{
int tNum = (int)threadnum;
int checkNum;
char *inUseFile = NULL;
int x=1;
FILE* file;
while(currentFile < 10){
if(inUseFile == NULL){//inUseFIle being used to check if a file is still being read
sem_wait(&semAccess);//critical section
inUseFile = fn[currentFile];
sem_post(&semAssign);
file = fopen(inUseFile, "r");
while(!feof(file)){
if(x % 1000 == 0 && tNum !=1){ //go for 1000 integers and then wait
sem_wait(&semAssign);
}
checkNum = getNum(file);
/*
*
*
*
* I think the issue is here
*
*
*
*/
if(checkNum > highestPrime[tNum]){
if(prime(checkNum)){
highestPrime[tNum] = checkNum;
}
}
x++;
}
fclose(file);
inUseFile = NULL;
}
currentFile++;
}
}
int main(int argc, char* argv[])
{
if(argc != 2){ //checks for number of arguements being passed
printf("To many ARGS\n");
return(-1);
}
else{//Sets thread cound to user input checking for correct number of threads
numberOfThreads = atoi(argv[1]);
if(numberOfThreads < 1 || numberOfThreads > 10){
printf("To many threads entered\n");
return(-1);
}
time_t preTime, postTime; //creating time variables
int i;
fn = malloc(10 * sizeof(char*)); //create file array and initialize
fn[0] = file1;
fn[1] = file2;
fn[2] = file3;
fn[3] = file4;
fn[4] = file5;
fn[5] = file6;
fn[6] = file7;
fn[7] = file8;
fn[8] = file9;
fn[9] = file10;
sem_init(&semAccess, 0, 1); //initialize semaphores
sem_init(&semAssign, 0, numberOfThreads);
highestPrime = malloc(numberOfThreads * sizeof(int)); //create an array to store each threads highest number
for(loop = 0; loop < numberOfThreads; loop++){//set initial values to 0
highestPrime[loop] = 0;
}
pthread_t calculationThread[numberOfThreads]; //thread to do the work
preTime = time(NULL); //start the clock
for(i = 0; i < numberOfThreads; i++){
pthread_create(&calculationThread[i], NULL, findPrimality, (void *)i);
}
for(i = 0; i < numberOfThreads; i++){
pthread_join(calculationThread[i], NULL);
}
for(i = 0; i < numberOfThreads; i++){
printf("this is a prime number: %d \n", highestPrime[i]);
}
postTime= time(NULL);
printf("Wall time: %ld seconds\n", (long)(postTime - preTime));
}
}
Yes I am trying to find the highest number over all. So I have made some head way the last few hours, rescucturing the program as spudd said, currently I am getting a segmentation fault due to my use of structures, I am trying to save the largest individual primes in the struct while giving them the right indices. This is the revised code. So in short what the first thread is doing is creating all the threads and giving them access points to a very large integer array which they will go through and find prime numbers, I want to implement semaphores around the while loop so that while they are executing every 2000 lines or the end they update a global prime number.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
#include <math.h>
#include <semaphore.h>
//Global variable declaration
char *file1 = "primes1.txt";
char *file2 = "primes2.txt";
char *file3 = "primes3.txt";
char *file4 = "primes4.txt";
char *file5 = "primes5.txt";
char *file6 = "primes6.txt";
char *file7 = "primes7.txt";
char *file8 = "primes8.txt";
char *file9 = "primes9.txt";
char *file10 = "primes10.txt";
int numberOfThreads;
int entries[10000000];
int entryIndex = 0;
int fileCount = 0;
char** fileName;
int largestPrimeNumber = 0;
//Register functions
int prime(int n);
int getNum(FILE* file);
void* findPrimality(void *threadNum);
void* assign(void *num);
typedef struct package{
int largestPrime;
int startingIndex;
int numberCount;
}pack;
//Beging main code block
int main(int argc, char* argv[])
{
if(argc != 2){ //checks for number of arguements being passed
printf("To many threads!!\n");
return(-1);
}
else{ //Sets thread cound to user input checking for correct number of threads
numberOfThreads = atoi(argv[1]);
if(numberOfThreads < 1 || numberOfThreads > 10){
printf("To many threads entered\n");
return(-1);
}
int threadPointer[numberOfThreads]; //Pointer array to point to entries
time_t preTime, postTime; //creating time variables
int i;
fileName = malloc(10 * sizeof(char*)); //create file array and initialize
fileName[0] = file1;
fileName[1] = file2;
fileName[2] = file3;
fileName[3] = file4;
fileName[4] = file5;
fileName[5] = file6;
fileName[6] = file7;
fileName[7] = file8;
fileName[8] = file9;
fileName[9] = file10;
FILE* filereader;
int currentNum;
for(i = 0; i < 10; i++){
filereader = fopen(fileName[i], "r");
while(!feof(filereader)){
char* tempString = malloc(20 *sizeof(char));
fgets(tempString, 20, filereader);
tempString[strlen(tempString)-1] = '\0';
entries[entryIndex] = atoi(tempString);
entryIndex++;
free(tempString);
}
}
//sem_init(&semAccess, 0, 1); //initialize semaphores
//sem_init(&semAssign, 0, numberOfThreads);
time_t tPre, tPost;
pthread_t coordinate;
tPre = time(NULL);
pthread_create(&coordinate, NULL, assign, (void**)numberOfThreads);
pthread_join(coordinate, NULL);
tPost = time(NULL);
}
}
void* findPrime(void* pack_array)
{
pack* currentPack= pack_array;
int lp = currentPack->largestPrime;
int si = currentPack->startingIndex;
int nc = currentPack->numberCount;
int i;
int j = 0;
for(i = si; i < nc; i++){
while(j < 2000 || i == (nc-1)){
if(prime(entries[i])){
if(entries[i] > lp)
lp = entries[i];
}
j++;
}
}
return (void*)currentPack;
}
void* assign(void* num)
{
int y = (int)num;
int i;
int count = 10000000/y;
int finalCount = count + (10000000%y);
int sIndex = 0;
pack pack_array[(int)num];
pthread_t workers[numberOfThreads]; //thread to do the workers
for(i = 0; i < y; i++){
if(i == (y-1)){
pack_array[i].largestPrime = 0;
pack_array[i].startingIndex = sIndex;
pack_array[i].numberCount = finalCount;
}
pack_array[i].largestPrime = 0;
pack_array[i].startingIndex = sIndex;
pack_array[i].numberCount = count;
pthread_create(&workers[i], NULL, findPrime, (void *)&pack_array[i]);
sIndex += count;
}
for(i = 0; i< y; i++)
pthread_join(workers[i], NULL);
}
//Functions
int prime(int n)//check for prime number, return 1 for prime 0 for nonprime
{
int i;
for(i = 2; i <= sqrt(n); i++)
if(n % i == 0)
return(0);
return(1);
}
Here is my latest update, having issues with my threads running, the only thread is thread 0 that is completing
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
#include <math.h>
#include <semaphore.h>
//Global variable declaration
char *file1 = "primes1.txt";
char *file2 = "primes2.txt";
char *file3 = "primes3.txt";
char *file4 = "primes4.txt";
char *file5 = "primes5.txt";
char *file6 = "primes6.txt";
char *file7 = "primes7.txt";
char *file8 = "primes8.txt";
char *file9 = "primes9.txt";
char *file10 = "primes10.txt";
sem_t semHold;
int numberOfThreads;
long unsigned int entries[10000000];
unsigned int entryIndex = 0;
int fileCount = 0;
char** fileName;
long unsigned int largestPrimeNumber = 0;
//Register functions
int prime(unsigned int n);
int getNum(FILE* file);
void* findPrimality(void *threadNum);
void* assign(void *num);
typedef struct package{
long unsigned int largestPrime;
unsigned int startingIndex;
unsigned int numberCount;
}pack;
pack pack_array[10];
//Beging main code block
int main(int argc, char* argv[])
{
if(argc != 2){ //checks for number of arguements being passed
printf("To many threads!!\n");
return(-1);
}
else{ //Sets thread cound to user input checking for correct number of threads
numberOfThreads = atoi(argv[1]);
if(numberOfThreads < 1 || numberOfThreads > 10){
printf("To many threads entered\n");
return(-1);
}
int threadPointer[numberOfThreads]; //Pointer array to point to entries
int i;
fileName = malloc(10 * sizeof(char*)); //create file array and initialize
fileName[0] = file1;
fileName[1] = file2;
fileName[2] = file3;
fileName[3] = file4;
fileName[4] = file5;
fileName[5] = file6;
fileName[6] = file7;
fileName[7] = file8;
fileName[8] = file9;
fileName[9] = file10;
FILE* filereader;
long unsigned int currentNum;
sem_init(&semHold, 0, 1);
for(i = 0; i < 10; i++){
filereader = fopen(fileName[i], "r");
while(fscanf(filereader, "%lu" , ¤tNum)!= EOF){
entries[entryIndex] = currentNum;
// while(entryIndex < 5){
//char* tempString = malloc(20 *sizeof(long unsigned int));
//fgets(tempString, 20, filereader);
//tempString[strlen(tempString)-1] = '\0';
//currentNum = atoi(tempString);
//printf("Test %lu\n",currentNum);
//entries[entryIndex] = atoi(tempString);
//entryIndex++;
//free(tempString);
//}
entryIndex++;
}
}
printf("Test %lu\n",entries[9999999]);
//sem_init(&semAccess, 0, 1); //initialize semaphores
//sem_init(&semAssign, 0, numberOfThreads);
time_t tPre, tPost;
pthread_t coordinate;
tPre = time(NULL);
pthread_create(&coordinate, NULL, assign, (void**)numberOfThreads);
pthread_join(coordinate, NULL);
tPost = time(NULL);
printf("Largest prime = %lu , time: %ld\n", largestPrimeNumber,(long)(tPost-tPre));
}
}
void* findPrime(void* pack_array)
{
pack* currentPack = pack_array;
unsigned int lp = currentPack->largestPrime;
unsigned int si = currentPack->startingIndex;
unsigned int nc = currentPack->numberCount;
int i;
printf("Starting index Count: %d\n", si);
for(i = si; i < nc; i++){
if(i%100000==0)
printf("Here is i: %d\n", i);
if(entries[i]%2 != 0){
if(entries[i] > currentPack->largestPrime){
if(prime(entries[i])){
currentPack->largestPrime = entries[i];
printf("%lu\n", currentPack->largestPrime);
if(currentPack->largestPrime > largestPrimeNumber)
sem_wait(&semHold);
largestPrimeNumber = currentPack->largestPrime;
sem_post(&semHold);
}
}
}
}
}
void* assign(void* num)
{
int y = (int)num;
int i;
int count = 10000000/y;
int finalCount = count + (10000000%y);
int sIndex = 0;
printf("This is count: %d\n", count);
printf("This is final count: %d\n", finalCount);
pthread_t workers[y]; //thread to do the workers
for(i = 0; i < y; i++){
printf("for thread %d Starting index: %d\n", i, sIndex);
if(i == (y-1)){
pack_array[i].largestPrime = 0;
pack_array[i].startingIndex = sIndex;
pack_array[i].numberCount = finalCount;
}
pack_array[i].largestPrime = 0;
pack_array[i].startingIndex = sIndex;
pack_array[i].numberCount = count;
pthread_create(&workers[i], NULL, findPrime, (void *)&pack_array[i]);
printf("thread created\n");
sIndex += count;
}
for(i = 0; i < y; i++)
pthread_join(workers[i], NULL);
}
//Functions
int prime(unsigned int n)//check for prime number, return 1 for prime 0 for nonprime
{
int i;
for(i = 2; i <= sqrt(n); i++)
if(n % i == 0)
return(0);
return(1);
}
OK here's part of my solution, it's missing most of main, and has some other simple stuff missing, if you choose to base your code around this you can do one of two things load all the data before starting your workers, or have the main thread load it while the workers are running, I did the latter in my complete version. However you'll have to do some work to get that to be handled correctly because currently the workers will never exit.
Also you might want to try adapting your single array code above based on this.
So if you load all the data before starting the workers you don't need the condition variable and they can just exit when next_chunk is NULL. I recommend you figure out how to get loading while the workers are running working because it'll be more efficient.
Hint: pthread_cond_broadcast()
Also missing is the actual worker function.
// A singly linked list of chunks of 1000 numbers
// we use it as a queue of data to be processed
struct number_chunk
{
struct number_chunk *next;
int size;
int nums[1000];
};
pthread_mutex_t cnklst_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t data_available = PTHREAD_COND_INITIALIZER;
struct number_chunk *next_chunk = NULL;
void load_chunks(char *filename)
{
FILE *in = fopen(filename, "r");
int done = 0;
int i;
if(in == NULL) {
fprintf(stderr, "Failed to open file %s\n", filename);
return;
}
// read in all the chunks of 1000 numbers from the file
while(!done) {
struct number_chunk *cnk = malloc(sizeof(struct number_chunk)); // allocate a new chunk
cnk->next = NULL;
for(i=0; i < 1000; i++) { // do the actual reading
char tmp[20];
if(fgets(tmp, 20, in) == NULL) { // end of file, leave the read loop
done = 1;
break;
}
cnk->nums[i] = atoi(tmp);
}
// need to do this so that the last chunk in a file can have less than 1000 numbers in it
cnk->size = i;
// add it to the list of chunks to be processed
pthread_mutex_lock(&cnklst_mutex);
cnk->next = next_chunk;
next_chunk = cnk;
pthread_cond_signal(&data_available); // wake a waiting worker
pthread_mutex_unlock(&cnklst_mutex);
}
fclose(in);
}
struct number_chunk *get_chunk()
{
struct number_chunk *cnk = NULL;
pthread_mutex_lock(&cnklst_mutex);
//FIXME: if we finish we will never exit the thread
// need to return NULL when all the work that there will ever be
// is done, altertitively load everything before starting the workers and
// get rid of all the condition variable stuff
while(next_chunk == NULL)
pthread_cond_wait(&data_available, &cnklst_mutex);
cnk = next_chunk;
if(next_chunk != NULL) next_chunk = next_chunk->next;
pthread_mutex_unlock(&cnklst_mutex);
return cnk;
}
The way my workers report the final max prime is to just do it at the end by looking at a single global variable and setting it or not based on the highest prime they found during their run. Obviously you'll need to synchronize for that.
Also note it uses a mutex rather than a semaphore because of the use of pthread_cond_wait() If you haven't covered condition variables yet just drop that stuff and load everything before starting your workers.
Also since this is homework, read my code try to understand it then without looking at it again try to write your own.
I would have changed it more but I'm not sure how because it's already basically a really generic producer/consumer example that's missing some bits :P
Another thing to try if you do decide to adopt the same strategy I did and have the loading running in the main thread while the workers work you could add a second condition variable and a counter to limit the number of chunks in the queue and have your workers wake up the main thread if they run out of work.