I am having an issue with my current code. I am working on a project where I am using threads to read a group of files from the terminal and tell how many lines there are in the individual and total grouping of files. My question is that when I run the code I get a core dump and when I run my code through gdb I get a segmentation fault at the pthread_create call. Is it because of my implementation or is it due to something else in my code?
#define NUM_THREADS 12
struct thread_data{
char *thread_id;
int count;
};
struct thread_data thread_data_array[NUM_THREADS];
void* filecount(void * thread_arg){
char thread_id;
int count;
struct thread_data *thread;
thread = (struct thread_data *) thread_arg;
thread_id = *thread->thread_id;
count = thread->count;
FILE *fp = fopen(&thread_id, "r");
if (fp == NULL) {
fprintf(stderr, "Cannot open %s\n", thread_id);
exit(-1);
}
for (char c = getc(fp); c != EOF; c = getc(fp))
if (c == '\n')
count++;
fclose(fp);
pthread_exit(NULL);
}
int main(int argc, char *argv[]){
if (argc == 1)
return 0;
pthread_t threads[argc];
int t, total_count, count;
total_count = 0;
for(t=1; t<argc; t++){
thread_data_array[t].thread_id = argv[t];
thread_data_array[t].count = count;
printf("Creating thread for file: %s",thread_data_array[t].thread_id);
///This is the line in question///
pthread_create(&threads[t], NULL,filecount,(void *) &thread_data_array[t]);
printf("File name: %s --- line count: %d", thread_data_array[t].thread_id, total_count);
total_count += thread_data_array[t].count;
}
printf("Total line count: %d", total_count);
pthread_exit(NULL);
}
To summarize some of the comments:
This
char thread_id;
thread_id = *thread->thread_id;
will give you the first character of the filename. So while &thread_id is the correct type (char *) for the first argument of fopen, its not a pointer to a null terminating string. This is undefined behaviour.
In
thread_data_array[t].count = count;
count is uninitialized, and its value is indeterminate. This is undefined behaviour.
You need to wait for each thread to finish before you use its result. pthread_join is the function to use here.
getc (fgetc) returns type int, which allows for the check against EOF. Narrowing to char removes the ability to properly test for EOF.
thread_data_array should match the threads array in size.
Here is a refactored program:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
struct thread_data {
char *thread_id;
int count;
};
void *filecount(void *thread_arg){
struct thread_data *arg = thread_arg;
FILE *fp = fopen(arg->thread_id, "r");
if (fp == NULL) {
fprintf(stderr, "Cannot open %s\n", arg->thread_id);
pthread_exit(NULL);
}
for (int c = getc(fp); c != EOF; c = getc(fp))
if (c == '\n')
arg->count++;
fclose(fp);
return NULL;
}
int main(int argc, char *argv[]){
if (argc == 1)
return 0;
argv++;
argc--;
pthread_t threads[argc];
struct thread_data thread_data_array[argc];
int total_count = 0;
for (int i = 0; i < argc; i++) {
thread_data_array[i].thread_id = argv[i];
thread_data_array[i].count = 0;
pthread_create(&threads[i], NULL, filecount,(void *) &thread_data_array[i]);
}
for (int i = 0; i < argc; i++) {
pthread_join(threads[i], NULL);
total_count += thread_data_array[i].count;
}
printf("Total line count: %d\n", total_count);
}
Related
i need to read a file which contains interger line called data.txt.i need to create threads and read line by line.if a thread has read a line other threads should skip it and should not read it.one thread for one line.i have tried a code but doesnt give any output
i have created threads in a for loop for lines counts.and passed the current value in the for loop as a parameter to thread function.
#include<stdio.h>
#include<string.h>
#include<pthread.h>
int main(){
int a,b,i;
pthread_mutex_t lock;
int getLineCount(){
FILE *fp;
char ch;
int linesCount=0;
fp=fopen("data.txt","r");
if(fp==NULL)
{
printf("File does not exist!!!\n");
return -1;
}
while((ch=fgetc(fp))!=EOF)
{
if(ch=='\n')
linesCount=linesCount+1;
}
fclose(fp);
return linesCount;
}
void *readLine(void *lineNumb){
printf("%d",5);
int lineN= (*(int *)lineNumb);
pthread_mutex_lock(&lock);
FILE* fp = fopen("data.txt", "r");
char line[256];
int i = 0;
while (fgets(line, sizeof(line), fp)) {
i++;
if(i == lineN)
{
fscanf(fp,"%d%d",&a,&b);
printf("%d \n",a+b);
}
}
fclose(fp);
pthread_mutex_unlock(&lock);
}
int lineCount = getLineCount()+1;
pthread_t tid[lineCount];
for (i = 1; i <= lineCount; i++) {
void *b =&i;
pthread_create(&tid[i], NULL,readLine,(void*)b);
pthread_mutex_destroy(&lock);
}
pthread_join(tid[1] ,NULL);
pthread_join(tid[2] ,NULL);
pthread_join(tid[3] ,NULL);
pthread_join(tid[4] ,NULL);
pthread_join(tid[5] , NULL);
return 0;
}
I am trying to create a thread and read from stdin inside the thread. In main() have dynamically allocated memory to a 2d array based on the size given as user input. In the thread I am reading from stdin and splitting it using strtok and adding it into the 2d array. I am not sure why there is a segmentation fault, searched SO and I seem to have handled all the cases related to strtok.
This is the program -
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int dimB;
int dimA;
char** buffer;
char* temp;
void *thread(void *threadid){
char *buf;//[30] = {};
size_t len = 0;
ssize_t read;
char *line = NULL;
char *each;
printf("Hello World!.\n");
while ((read = getline(&line, &len, stdin)) != -1) {
printf("%s || \n", line);
each = strtok(line," ,()");
printf("************************%s ", each);
while(each != NULL){
buf = each;
strcpy(buffer[0][0], buf);
printf("%s", buf);
each = strtok(NULL," ,()");
}
}
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t tidMpr;
long r;
int i;
dimB = atoi(argv[1]);
dimA = atoi(argv[2]);
pthread_t tidRdr[dimA];
buffer = malloc(dimA * sizeof(char*));
temp = malloc(dimA * dimB * sizeof(char));
for (i = 0; i < dimA; i++) {
buffer[i] = temp + (i * dimB);
}
//Create thread Thread
pthread_create(&tidMpr, NULL, thread, NULL);
free(temp);
free(buffer);
pthread_exit(NULL);
}
The 2d array memory allocation is from this question - How do I work with dynamic multi-dimensional arrays in C?.
I know I am writing everything to buffer[0][0], but that is so that I can store each in a buffer array buffer[0][1], buffer[0][2] later on based on some logic. But that shouldn't be a problem now right?
Also line is printing the correct value, whatever it is reading from stdin. So, probably strtok is the problem.
Another very similar program produces the desired output. This -
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
typedef struct { char action; int score; } Rules;
Rules rules[5] = {{'P',50}, {'L',20}, {'D',-10}, {'C',30}, {'S',40}};
int findScore(Rules* rules, char action){
int i;
for(i=0; i<5; i++){
if(rules[i].action == action)
return rules[i].score;
}
fprintf(stderr, "Action not present! Exiting...\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]){
FILE *fp;
char inputTuple[30] = {};
char buf[30] = {};
char* oB;
oB = "(";
char* cB;
char* co = ",";
cB = ")";
fp = fopen(argv[1], "r");
int score;
char *each;
size_t len = 0;
ssize_t read;
char * line = NULL;
char *eacharray;
int u = 0;
char *outputTuple;
int pad = 0;
int g;
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
each = strtok(line," ,()");
while(each != NULL){
if(u%3 == 0){
outputTuple = (char *) malloc(1 + strlen(each)+ strlen(oB) );
strcpy(outputTuple, oB);
strcat(outputTuple, each);
} else if(u%3 == 1){
char q = *each;
score = findScore(rules, q);
} else if(u%3 == 2){
char * str3 = (char *) malloc(1 + strlen(outputTuple)+ strlen(co) );
strcpy(str3, outputTuple);
strcat(str3, co);
char *str4 = (char *) malloc(1 + strlen(str3)+ strlen(each) );
strcpy(str4, str3);
strcat(str4, each);
for(pad = strlen(each); pad<15; pad++)
strcat(str4," ");
sprintf(buf, "%s,%d)\n", str4, score);
printf("%s", buf);
free(outputTuple);
free(str3);
free(str4);
}
each = strtok(NULL," ,()");
u++;
}
u = 0;
}
fclose(fp);
return 0;
}
Update :
strcpy(buffer[0][0], buf); seems to be the problem. When I comment it, it is producing the output. I dont understand why is that causing a problem.
So I'm working on a multithreaded word count program in c and I was having some problems with my code, while searching here I found an old question that was similar to my own project. Rather than trying to rework my code which was full of problems, I decided to try and get this other one working, then modify it to make what I want.
The code takes a txt file as input. The problem is when you run the program there is a segmentation fault.
Here's the code:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
struct thread_data{
FILE *fp;
long int offset;
int start;
int blockSize;
};
int words=0;
void *countFrequency(void* data){
struct thread_data* td=data;
char *buffer = malloc(td->blockSize);
int i,c;
i=0;c=0;
enum states { WHITESPACE, WORD };
int state = WHITESPACE;
fseek(td->fp, td->offset, td->start);
char last = ' ';
while ((fread(buffer, td->blockSize, 1, td->fp))==1){
if ( buffer[0]== ' ' || buffer[0] == '\t' ){
state = WHITESPACE;
}
else if (buffer[0]=='\n'){
state = WHITESPACE;
}
else {
if ( state == WHITESPACE ){
words++;
}
state = WORD;
}
last = buffer[0];
}
free(buffer);
pthread_exit(NULL);
return NULL;
}
int main(int argc, char **argv){
int nthreads, id, blockSize,len;
FILE *fp;
pthread_t *threads;
if (argc < 2){
fprintf(stderr, "Usage: ./a.out <file_path>");
exit(-1);
}
if((fp=fopen(argv[1],"r"))==NULL){
printf("Error opening file");
exit(-1);
}
printf("Enter the number of threads: ");
scanf("%d",&nthreads);
struct thread_data data[nthreads];
threads = malloc(nthreads*sizeof(pthread_t));
fseek(fp, 0, SEEK_END);
len = ftell(fp);
printf("len= %d\n",len);
blockSize=(len+nthreads-1)/nthreads;
printf("size= %d\n",blockSize);
for(id = 0; id < nthreads; id++){
data[id].fp=fp;
data[id].offset = blockSize;
data[id].start = id*blockSize+1;
}
data[nthreads-1].start=(nthreads-1)*blockSize+1;
for(id = 0; id < nthreads; id++)
pthread_create(&threads[id], NULL, &countFrequency,&data[id]);
for(id = 0; id < nthreads; id++)
pthread_join(threads[id],NULL);
fclose(fp);
printf("%d\n",words);
return 0;
}
And here's a link to the original post: original
You invoked undefined behavior by using indeterminate value of uninitalized variable having automatic storage duration nthreads in struct thread_data data[nthreads];.
Try moving the line after scanf("%d",&nthreads);.
I'm trying to read words from a file (which has one word per line) and store these words in a 2D String array such that each row contains all the words that begins with same letter/character. But when I try to print the array all the elements are shown to be "null".
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#define numberOfMappers 2
char *buffer1[10];
char *buffer2[10];
int add = 0;
int rem = 0;
int num = 0;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c_mapper = PTHREAD_COND_INITIALIZER;
pthread_cond_t c_pooler = PTHREAD_COND_INITIALIZER;
void *pooler (void *param);
void *mapper (void *param);
void printBuffer1();
int main(int argc, char *argv[]) {
pthread_t tid1;
int i;
if(pthread_create(&tid1, NULL, pooler, NULL) != 0) {
fprintf(stderr, "Unable to create producer thread\n");
exit(1);
}
pthread_join(tid1, NULL);
printBuffer1();
return 0;
}
void *pooler(void *param) {
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("file.txt", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
int i;
for (i = 0; i < 10; i ++) {
buffer1[i] = line;
}
fflush(stdout);
return 0;
}
void printBuffer1() {
int i;
for (i = 0; i < 10; i ++) {
printf("%s\t", buffer1[i]);
}
}
You forgot to call getline().
getline() reuses or reallocates the line buffer if you pass the previous one, thus the old line gets lost. You can prevent this by clearing the line pointer before each call.
So, insert
line = NULL, len = 0;
if (getline(&line, &len, fp) < 0) break;
before
buffer1[i] = line;
I have a file which contains a list of filenames in which I wanna search for a word and replace it
I modified the code a little just to show only relevant parts here
The problem is that if I have only one file in that list, it won't process it with multi threads because the threads are working only if I have multiple files
So I want to keep the current threads configuration but I wanna add some threads at the processing part
I have this code:
struct words_list {
char word[20];
struct words_list * next;
};
FILE * INFILE;
int num_thread = 10;
// Mutex variables
pthread_mutex_t input_queue;
pthread_mutex_t word_list;
int main(int argc,char **argv)
{
//some code is missing
if((INFILE = fopen(myfile,"r")) == NULL) {
fprintf(stderr,"Can't open input file\n");
exit(0);
}
for(i = 0 ; i < number_thread; i++)
{
if(pthread_create(&thread_id[i],NULL,&search,NULL) != 0)
{
i--;
fprintf(stderr,RED "\nError in creating thread\n" NONE);
}
}
for(i = 0 ; i < number_thread; i++)
if(pthread_join(thread_id[i],NULL) != 0)
{
fprintf(stderr,RED "\nError in joining thread\n" NONE);
}
fflush(INFILE);
fclose(INFILE);
}
void * search(void * data)
{
char file[20];
while (!feof(INFILE))
{
if (fgets(file,sizeof(file),INFILE) != NULL)
{
if (strlen(file) < 8)
break;
if (file[strlen (file) - 1] == '\n')
file[strlen (file) - 1] = '\0';
}
process(file);
}
return NULL;
}
void process(char *filename)
{
char buff[512];
char word[20];
struct words_list * curr_word = first_word;
if(verbose != 0)
fprintf(stderr,"Processing: %s\n",filename);
while(curr_word != NULL)
{
//some code missing
pthread_mutex_lock(&word_list);
strncpy(word,curr_word->word,sizeof(word) - 1);
pthread_mutex_unlock(&word_list);
**//replace_word must run with multiple threads**
ret = replace_word(word,buff,sizeof(buff));
//end of threads part
//code missing
}
}
How can I add other pthreads at the bold part so it can process with multiple threads each file?
Instead of assigning one thread per file. Why shouldn't you allocate a thread to process portion of each file. As shown below, I allocated a thread for every 50 bytes of data in a file. In this technique, even if you have only one file in the list, you can still use multiple threads to parse it. Hope it helps.
#include "stdio.h"
#include "pthread.h"
#include "sys/stat.h"
#include "string.h"
#include "fcntl.h"
#define TOTAL_NUMBER_THREADS 100
struct words_list {
char word[20];
struct words_list * next;
};
struct file_segment {
char filename[50];
size_t foffset;
size_t size;
}fs[TOTAL_NUMBER_THREADS];
FILE * INFILE;
int num_thread=0;
// Mutex variables
pthread_mutex_t input_queue;
pthread_mutex_t word_list;
pthread_t thread_id[TOTAL_NUMBER_THREADS];
void *process( void *arg);
void segment_file(char *filename)
{
int fd;
int offset=0;
struct stat statbuf;
size_t size;
fd = open(filename, O_RDONLY);
if(fd < 0)
{
perror("fopen");
return;
}
fstat(fd, &statbuf);
size=statbuf.st_size;
while((offset < size) && (num_thread <= 100))
{
strncpy(fs[num_thread].filename, filename, sizeof(fs[num_thread].filename));
fs[num_thread].foffset=offset;
fs[num_thread].size=(size>50)?50:size;
offset+=fs[num_thread].size;
if(pthread_create(&thread_id[num_thread],NULL,&process,&fs[num_thread]) != 0)
{
fprintf(stderr,"\nError in creating thread\n");
}
num_thread++;
}
return;
}
void *process( void *arg)
{
char buf[50];
struct file_segment *fs;
char word[20];
//struct words_list * curr_word = first_word;
fs = (struct file_segment *) arg;
FILE *fp;
fp=fopen(fs->filename, "r");
fseek(fp, fs->foffset, SEEK_SET);
fread(buf,1,fs->size,fp);
while(curr_word != NULL)
{
//some code missing
pthread_mutex_lock(&word_list);
strncpy(word,curr_word->word,sizeof(word) - 1);
pthread_mutex_unlock(&word_list);
**//replace_word must run with multiple threads**
ret = replace_word(word,buff,sizeof(buff));
//end of threads part
//code missing
}
//printf("Filename: %s\n Info: %s\n", fs->filename, buf);
printf("%s", buf);
return;
}
int main(int argc,char **argv)
{
//some code is missing
char file[50];
int i;
if((INFILE = fopen("list.txt","r")) == NULL) {
fprintf(stderr,"Can't open input file\n");
return 0; }
while (!feof(INFILE))
{
if (fgets(file,sizeof(file),INFILE) != NULL)
{
if (strlen(file) < 8)
break;
if (file[strlen (file) - 1] == '\n')
file[strlen (file) - 1] = '\0';
}
segment_file(file);
}
for(i = 0 ; i < num_thread; i++)
if(pthread_join(thread_id[i],NULL) != 0)
{
fprintf(stderr,"\nError in joining thread\n");
}
fflush(INFILE);
fclose(INFILE);
}