MPI SEND / RECV ARRAY OF STRINGS in standard C - c

Okay, so I've been struggling with this problem for a few days. I'm trying to distribute an array of strings to various nodes in my Raspberry Pi 4 computing cluster using its most recent version of openmpi. I figured this was a perfect way to learn how clustering works, but I am completely lost at this point and have no direction. For the current set of code, I'm getting a segmentation fault, but when I follow other sets of instructions, I will sometimes receive only the first character of the first string, and null every other character. Those times are when instead of the current array send line, the first argument would be &(NodeOne[0][0]). Most of these sets of instructions are 6-9 years old.
Does anyone have any ideas to make the code do more than compile?
#include <stdlib.h>
#include <curl/curl.h>
#include <string.h>
#include <mpi.h>
#define NUMC 4
void *set_Stats(void *z);
struct Tickers {
char ** x;
int length;
};
struct Tickers getTickers()
{
CURL *curl = curl_easy_init();
char line[300];
struct Tickers tickers;
int length = 0;
char url[60] = "ftp://ftp.nasdaqtrader.com/symboldirectory/nasdaqtraded.txt";
if(curl)
{
FILE *temp = tmpfile();
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)temp);
curl_easy_perform(curl);
if(temp)
{
rewind(temp);
char c = fgetc(temp);
while (fgets(line,sizeof(line),temp))
{
length++;
}
rewind(temp);
length = length - 2;
tickers.length = length;
tickers.x = malloc(length * sizeof(char*));
fgets(line, sizeof(line), temp);
fgets(line, sizeof(line), temp);
for(int count = 0; count < length; count++)
{
char *string = line + 2;
int tickLen = strstr(string, "|") - string;
char sub[tickLen];
tickers.x[count] = malloc(tickLen);
strncpy(sub, string, tickLen);
sub[tickLen] = '\0';
strcpy(tickers.x[count], sub);
fgets(line, sizeof(line), temp);
}
fclose(temp);
}
}
curl_easy_cleanup(curl);
return tickers;
}
char ** allocate_DD(int rows, int cols)
{
char *data = (char *)malloc(rows*cols);
char **array= (char **)malloc(rows*sizeof(char*));
for(int i = 0; i < rows; i++)
array[i] = &(data[cols*i]);
return array;
}
int main() //Designed for one master, three slaves
{
int my_id;
MPI_Init(NULL,NULL);
MPI_Comm_rank(MPI_COMM_WORLD, &my_id);
MPI_Status status;
int firstNodeLength;
if(my_id == 0) // meaning this process is a host job
{
struct Tickers tickers = getTickers();
int length = tickers.length / 3;
int remainder = tickers.length % 3;
char ** NodeOneTicks = allocate_DD(length + remainder, 6);
//char ** NodeTwoTicks = allocate_DD(length, 6);
//char ** NodeThrTicks = allocate_DD(length, 6);
int count = 0;
int x = 0;
while(count < length + remainder)
{
strcpy(NodeOneTicks[x], tickers.x[count]);
NodeOneTicks[x][5] = '\0';
count++;
x++;
}
x = 0;
firstNodeLength = length + remainder;
printf("%d\n", firstNodeLength);
MPI_Send(&firstNodeLength,1, MPI_INT,1,1000,MPI_COMM_WORLD);
MPI_Send(NodeOneTicks,firstNodeLength,MPI_CHAR,1,1001,MPI_COMM_WORLD);
}
else // must be slave process
{
int myLen;
int x = 0;
int ierr = MPI_Recv(&myLen,1,MPI_INT,0,MPI_ANY_TAG,MPI_COMM_WORLD,&status);
printf("%d\n", myLen);
char ** myTicks = allocate_DD(myLen,6);
ierr = MPI_Recv(myTicks[0], myLen,MPI_CHAR,0,MPI_ANY_TAG,MPI_COMM_WORLD,&status);
myTicks[0][5] = '\0';
printf("%s\n", myTicks[0]);
}
MPI_Finalize();
}

It turned out that the problem came from the original array returned by getTickers(). Even though it printed fine when the function was non-mpi, it was overflowed at certain points, rendering the MPI array to be garbage. Thank you to #GillesGouaillardet for helping / basically solving the problem for me!

Related

How to order split command line arguments in lexicographical order using a function?

I'm working on a program that takes command line arguments and splits them in half and then orders them in lexicographical order.
For example:
hello, world!
would turn into:
he
ld!
llo
wor
I have a main method that reads through the arguments, a function that splits the arguments, and finally a function that is supposed to order the halves in lexicographical order. I can't get this to run properly because of argument type errors in the lexicographicalSort method and an incompatible pointer type in the main method. I'm having issues to correct these syntax errors, how exactly would I correct them? Also, is there anything here that would cause logical errors? This is what I have so far:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int splitString(char arg[], int n)
{
int len = strlen(arg);
int len1 = len/2;
int len2 = len - len1; // Compensate for possible odd length
char *s1 = malloc(len1 + 1); // one for the null terminator
memcpy(s1, arg, len1);
s1[len1] = '\0';
char *s2 = malloc(len2 + 1); // one for the null terminator
memcpy(s2, arg + len1, len2);
s2[len2] = '\0';
printf("%s\n", s1);
printf("%s\n", s2);
free(s1);
free(s2);
return 0;
}
int lexicographicalSort(char *arg[], int n)
{
char temp[50];
for(int i = 0; i < n; ++i)
scanf("%s[^\n]",arg[i]);
for(int i = 0; i < n - 1; ++i)
for(int j = i + 1; j < n ; ++j)
{
if(strcmp(arg[i], arg[j]) > 0)
{
strcpy(temp, arg[i]);
strcpy(arg[i], arg[j]);
strcpy(arg[j], temp);
}
}
for(int i = 0; i < n; ++i)
{
puts(arg[i]);
}
return 0;
}
int main(int argc, char *argv[])
{
if (argc > 1)
{
for (int i = 1; i < argc; i++)
{
int j = 1;
int k = strlen(argv[i]);
splitString(argv[i], j);
lexicographicalSort(argv[i], j);
}
}
}
Basic scheme is simple. Make an array of tuples {start_pointer, length}. Do some programming on args to split the args. Fill in the array as appropriate. Make sorting with qsort, or any other sort of your choise.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
char *s = "hello, world! . hello.....";
char *pc;
int i, n, nargs;
struct pp{
char *p;
int l;
};
struct pp args[10], hargs[20];
struct pp *pargs;
int cmp(const void * v0, const void * v1) {
struct pp *pv0 = v0, *pv1 = v1;
return strncmp(pv0->p, pv1->p, pv0->l);
}
int main(void)
{
for(pc = s, i = 0; *pc; ++i){
sscanf(pc, "%*[^ ]%n", &n);
if(n > 0){
args[i].p = pc;
args[i].l = n;
}
for(pc += n, n = 0; isspace(*pc); ++pc);
}
for(nargs = i, i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, args[i].l, args[i].p);
putchar('\n');
for(i = 0, pargs = hargs; i < nargs; ++i){
if(args[i].l == 1){
pargs->p = args[i].p;
pargs->l = 1;
pargs = pargs + 1;
}else {
pargs->p = args[i].p;
pargs->l = args[i].l / 2;
pargs = pargs + 1;
pargs->p = args[i].p + args[i].l / 2;
pargs->l = args[i].l - args[i].l / 2;
pargs = pargs + 1;
}
}
putchar('\n');
for(nargs = pargs - hargs, i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, hargs[i].l, hargs[i].p);
qsort(hargs, nargs, sizeof(struct pp), cmp);
putchar('\n');
for(i = 0; i < nargs; ++i)
printf("%d arg is: %.*s\n", i, hargs[i].l, hargs[i].p);
return 0;
}
https://rextester.com/GSH22767
Upon splitting a C string, one needs one extra char to store extra null-terminator. There is one answer that bypasses this by storing the length. For completeness, this is closer to your original intention: allocating enough space to copy the programmes arguments. It probably works slower, but one is free to use the strings elsewhere in the programme.
#include <stdlib.h> /* malloc free EXIT qsort */
#include <stdio.h> /* fprintf */
#include <string.h> /* strlen memcpy */
#include <errno.h> /* errno */
static int strcompare(const void *a, const void *b) {
const char *a_str = *(const char *const*)a, *b_str = *(const char *const*)b;
return strcmp(a_str, b_str);
}
int main(int argc, char **argv) {
char *spacev = 0, **listv = 0;
size_t spacec = 0, listc = 0;
int is_done = 0;
do { /* "Try." */
int i;
char *sv;
size_t j;
/* This requires argc > 1. */
if(argc <= 1) { errno = EDOM; break; }
/* Allocate maximum space. */
for(i = 1; i < argc; i++) spacec += strlen(argv[i]) + 2;
if(!(spacev = malloc(spacec)) || !(listv = malloc(argc * 2))) break;
sv = spacev;
/* Copy and split the arguments. */
for(i = 1; i < argc; i++) {
const char *const word = argv[i];
const size_t word_len = strlen(word),
w0_len = word_len / 2, w1_len = word_len - w0_len;
if(w0_len) {
listv[listc++] = sv;
memcpy(sv, word, w0_len);
sv += w0_len;
*(sv++) = '\0';
}
if(w1_len) {
listv[listc++] = sv;
memcpy(sv, word + w0_len, w1_len);
sv += w1_len;
*(sv++) = '\0';
}
}
/* Sort. */
qsort(listv, listc, sizeof listv, &strcompare);
for(j = 0; j < listc; j++) printf("%s\n", listv[j]);
is_done = 1;
} while(0); if(!is_done) {
perror("split");
} {
free(spacev);
free(listv);
}
return is_done ? EXIT_SUCCESS : EXIT_FAILURE;
}
It is simpler than your original; instead of allocating each string individually, it counts the maximum number of chars needed (plus two for two null terminators) and allocates the block all at once (space.) The pointers to the new list also need allocating, the maximum is 2 * argc. Once you copy and modify the argument list, one has an actual array of strings that one can qsort.

What's wrong with my Heap's Algorithm code?

My homework requires me to write a program that takes a string from the terminal (argc and argv) and print every possible permutation. I have tried to use Heap's Algorithm, but it doesn't seem to be working out. Below is my function.
char **getPermutation(char * in)
{
//n is the size of the input string.
int n = strlen(in);
int count[n];
int counter= 0;
char copy[n];
char **permutations = malloc(sizeof(char*)*(factorial(n)));
permutations[0] = in;
strcpy(in, copy);
counter++;
for( int i = 1; i < n;)
{
if (count[i] < i){
if (i%2==0){
swap(&in[0],&in[i]);
}
else
{
swap(&in[count[i]],&in[i]);
}
permutations[counter] = in;
strcpy(in, copy);
counter++;
count[i]++;
i = 1;
}
else
{
count[i] = 0;
i++;
}
}
return permutations;
}
The function must return the pointer to the character pointer as specified by the instructions. That's also why there are so many variables (although, I'm not really sure what to do with the copy of the string. I'm fairly sure I need it). Testing shows that the program will loop, often too much and eventually hit a seg fault. It doesn't seem like the swapped strings make it into the returned array on top of that.
Below is a rework of your code with cleaned up memory allocation and it addresses some problems mentioned in the above comments. Additionally, you have a bug in your algorithm, this statement strcpy(in, copy); keeps you from getting all the permutations (causes repeats instead.) This code works but isn't finished, it can use more error checking and other finishing touches:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
unsigned int factorial(unsigned int n)
{
/* ... */
}
void swap(char *a, char *b)
{
/* ... */
}
char **getPermutations(const char *input)
{
char *string = strdup(input);
size_t length = strlen(string);
char **permutations = calloc(factorial(length), sizeof(char *));
int *counts = calloc(length, sizeof(int)); // point to array of ints all initialized to 0
int counter = 0;
permutations[counter++] = strdup(string);
for (size_t i = 1; i < length;)
{
if (counts[i] < i)
{
if (i % 2 == 0)
{
swap(&string[0], &string[i]);
}
else
{
swap(&string[counts[i]], &string[i]);
}
permutations[counter++] = strdup(string);
counts[i]++;
i = 1;
}
else
{
counts[i++] = 0;
}
}
free(counts);
free(string);
return permutations;
}
int main(int argc, char *argv[])
{
char *string = argv[1];
char **permutations = getPermutations(string);
unsigned int total = factorial(strlen(string));
for (unsigned int i = 0; i < total; i++)
{
printf("%s\n", permutations[i]);
}
free(permutations);
return 0;
}
OUTPUT
> ./a.out abc
abc
bac
cab
acb
bca
cba
>

segmentation fault when calling c function on ruby

I am trying to extends my Ruby code with a C functions. The C code compiles without warning. But When I try to run the ruby code, I got a segmentation fault:
I have this c code:
#include <ruby.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "nessie.h"
/* #define TRACE_INTERMEDIATE_VALUES */
/*
* The number of rounds of the internal dedicated block cipher.
*/
#define R 10
VALUE rb_mExample;
VALUE rb_cClass;
// ...
static char* displayHash(const unsigned char array[], int length){
int i, k;
char *str;
str = malloc(3 * length + 1);
if (str == NULL) {
return NULL;
}
k = 0;
str[0] = '\0';
for (i = 0; i < length; i++){
char hex[3];
if (i % 32 == 0){
str[k++] = ' ';
}
if (i % 8 == 0){
str[k++] = ' ';
}
snprintf(hex, sizeof(hex), "%02X", array[i]);
str[k++] = hex[0];
str[k++] = hex[1];
}
str[k] = '\0';
return str;
}
VALUE
print_string(VALUE class, VALUE *valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
int i;
for (i = 0; valor[i] != '\0'; i++);
int sizeo = i;
NESSIEinit(&w);
NESSIEadd((u8*)valor, 8*sizeo, &w);
NESSIEfinalize(&w, digest);
return (VALUE) displayHash(digest, DIGESTBYTES);
}
void
Init_example(){
rb_mExample = rb_define_module("Example");
rb_cClass = rb_define_class_under(rb_mExample, "Class", rb_cObject);
rb_define_method(rb_cClass, "print_string", print_string, 1);
}
and this Ruby code:
require "example"
def print
e = Example::Class.new
e.print_string("ruby")
end
When I run the ruby code, I got a segmentation fault.
EDIT: gist with log info
https://gist.github.com/psantos10/f07484afa26ce0e55181
Where I failing? I am new in C language.
EDIT:
I changed my "print_string" to look like this:
VALUE
print_string(VALUE class, VALUE *valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
int i;
for (i = 0; valor[i] != '\0'; i++);
int sizeo = i;
NESSIEinit(&w);
NESSIEadd((u8*)valor, 8*sizeo, &w);
NESSIEfinalize(&w, digest);
return rb_str_new(displayHash(digest, DIGESTBYTES), 128);
}
whith that, segmentation fault gone. But the string returned is coming with a strange characters like:
"ruby\x00\x00\x00\x00\x00No error detected.\x00\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD80x\xC0\x18`\x18\x18&F\xAF\x05#\x8C##\xB8\x91\xF9~\xC6?\xC6\xC6\xFB\xCDo\x13\xE8\x87\xE8\xE8\xCB\x13\xA1L\x87&\x87\x87\x11mb\xA9\xB8\xDA\xB8\xB8\t\x02\x05\b\x01\x04\x01\x01\r\x9EnBO!OO\x9Bl\xEE\xAD6\xD866\xFFQ\x04Y\xA6\xA2\xA6\xA6\f\xB9\xBD\xDE\xD2o\xD2"
When the correct must be only:
"ruby"
EDIT 3:
Making this change:
VALUE
print_string(VALUE class, VALUE *valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
/*
int i;
for (i = 0; valor[i] != '\0'; i++);
int sizeo = i;
*/
NESSIEinit(&w);
NESSIEadd((u8*)"ruby", 8*4, &w);
NESSIEfinalize(&w, digest);
return rb_str_new(displayHash(digest, DIGESTBYTES), 128);
}
the correct value are returned.
Then I try to to that:
VALUE
print_string(VALUE class, VALUE *valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
/*
int i;
for (i = 0; valor[i] != '\0'; i++);
int sizeo = i;
*/
NESSIEinit(&w);
NESSIEadd((u8*)"ruby", 8*4, &w);
NESSIEfinalize(&w, digest);
return rb_str_new2(valor);
}
Expecting "ruby" string to be returned. But not. It returns: "\x05"
What that mean?
for (i = 0; i < length; i++)
Inside this loop for each passing if condition you increment k so by doing this you will be having array out of bound access hence the crash.
Make sure the
char *str = malloc( 3 * length + 1);
is not
char *str = malloc( 3 * (length + 1));
For Eg:
Have value of length = 2;
char *str = malloc(7);
Now in the for loop you increment k 4 times.
k = 4;
Now after the second iteration if you exit the loop then
k=8;
So str[8] is not a valid access and might lead to crash
Before all, let me thanks #FrederickCheung for give me the right direction.
The solution code is:
VALUE
print_string(VALUE class, VALUE valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
VALUE info;
// Note here I must convert the Ruby VALUE type to C type. Thats is the trick.
char* valor2 = RSTRING_PTR(valor);
int i;
for (i = 0; valor2[i] != '\0'; i++);
int sizeo = i;
NESSIEinit(&w);
NESSIEadd((u8*)valor2, 8*sizeo, &w);
NESSIEfinalize(&w, digest);
info = rb_str_new_cstr(displayHash(digest, DIGESTBYTES));
return info;
}
For who want to see where this code was used, can access: https://github.com/AngoDev/kryptonita

Getting null values in my array of struct in c, improper freeing

I had my program printing out the words in a file and incrementing when they appeared more than once. I am now getting just "NULL" and the count as "17" instead. I can't find anything that I changed but am not sure if it is because I haven't figured out how to properly free up my arrays.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BASE 5
#define MAX 50
typedef char *string;
struct wordCount
{
string word;
unsigned int count;
};
int main (void)
{
unsigned int i;
unsigned int found;
unsigned int arraysize;
unsigned int newsize;
char temp [40];
struct wordCount* wordArray;
FILE *infile;
arraysize = 0;
infile = fopen("input.txt","r");
wordArray = malloc(BASE * sizeof(struct wordCount));
/*store in word from infile to struct, increment counter each time it appears*/
while (fscanf(infile, "%s", temp) == 1) {
found = 0;
for (i = 0; i < arraysize; i++){
if(strcmp(temp,wordArray[i].word) == 0){
wordArray[i].count++;
found++;
}
}
if (found== 0){
if (arraysize<BASE){
wordArray[arraysize].word = (char
*)malloc((strlen(temp)+1) * sizeof(char));
strcpy(wordArray[arraysize].word,temp);
wordArray[arraysize].count = 1;
arraysize++;
} else {
wordArray = realloc(wordArray, arraysize * sizeof(struct wordCount));
wordArray[arraysize].word = (char *)malloc((strlen(temp)+1) *
sizeof(char));
strcpy(wordArray[arraysize].word,temp);
wordArray[arraysize].count = 1;
arraysize++;
}
}
}
fclose(infile);
/*newsize = SearchAndDestroy(wordArray, arraysize); */
for (i = 0; i < arraysize; i++) {
printf("%s ", wordArray[arraysize].word);
printf("%d\n", wordArray[arraysize].count);
/*free(wordArray[i].word);*/
}
/* and when done:*/
free(wordArray);
return 0;
}
You aren't tracking things properly. You need to pay more attention to the fact that "How many words I have", "how many words I have room for", and "how many words I would like to have room for" are three distinct items that need to all be tracked separately. In particular, it doesn't look like your call to realloc() is correct.

Threading across multiple files

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" , &currentNum)!= 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.

Resources