У меня есть программа, которая должна принимать в командной строке имя_файла, строку имя_строки (слово) и целое число (число потоков) в качестве аргументов.Затем программа создает эти многочисленные потоки для подсчета того, сколько раз в файле встречается имя_строки - имя_файла.
Серийный код выполняется правильно.Многопоточный код имеет следующие проблемы:
- Это приводит к дампу ядра - ошибка сегментации.
- Дает неправильный счетчик.
Я добавил некоторую отладкузаявления:
Он показывает неправильные номера строк, когда я пытаюсь напечатать, какой номер строки проверяется по какому номеру потока.
#include <stdio.h>
// #include <conio.h> - Does not exist in gcc
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define MAX_LINE_LENGTH 4096
#define MAX_WORD_SIZE 64
#define MAX_THREAD_COUNT_PER_PROCESS 64
// Important - in GCC - for pthread functions in addition to include pthread.h must also use flag -lpthread in compilation command
// gcc -w -o main main_multithreaded.c -lpthread
typedef unsigned int uint;
typedef struct {
uint valid;
uint line_num;
char* line;
} struct_line;
volatile struct_line buffer[MAX_THREAD_COUNT_PER_PROCESS];
pthread_mutex_t *buffer_mutex;
pthread_t* threads;
typedef struct {
FILE* fp;
} read_pthread_argv_type;
read_pthread_argv_type read_pthread_argv;
void read_file(void* read_pthread_argv)
{
read_pthread_argv_type* i_read_pthread_argv;
i_read_pthread_argv = (read_pthread_argv_type*) read_pthread_argv;
FILE* local_file_ptr;
local_file_ptr = i_read_pthread_argv->fp;
char *line;
uint i, line_count = 0, line_length;
line = (char*) malloc (MAX_LINE_LENGTH);
while (fgets(line, MAX_LINE_LENGTH, local_file_ptr) != NULL)
{
line_length = strlen (line);
while (pthread_mutex_lock(buffer_mutex))
{}
for (i = 0; i<MAX_THREAD_COUNT_PER_PROCESS; i++)
{
if (buffer[i].valid != 1)
{
break;
}
}
buffer[i].line = (char*) malloc (line_length);
buffer[i].line = line;
buffer[i].line_num = line_count;
buffer[i].valid = 1;
// printf ("Line %u of file read and saved as %s \n", buffer[i].line_num, buffer[i].line);
line_count++;
pthread_mutex_unlock(buffer_mutex);
}
printf ("File read finished \n");
free (line);
pthread_exit(NULL);
}
typedef struct {
char* string_to_search;
uint thread_num;
uint count;
} count_pthread_argv_type;
count_pthread_argv_type count_pthread_argv[MAX_THREAD_COUNT_PER_PROCESS];
int count_string (void* pthread_argv_i)
{
// Declare variables for line and word
char *line, *word;
line = (char*) malloc (MAX_LINE_LENGTH);
word = (char*) malloc (MAX_WORD_SIZE);
// Declare and initiaize count
uint count = 0, wordcount_in_line;
uint i, k = 0;
int j;
count_pthread_argv_type* i_pthread_argv;
i_pthread_argv = (count_pthread_argv_type*)pthread_argv_i;
char* local_string_to_search = i_pthread_argv->string_to_search;
uint local_thread_num = i_pthread_argv-> thread_num;
//printf (" For thread %u -> Local string to search = %s \n starting line = %u and num_lines = %u \n", \
local_thread_num, local_string_to_search, local_starting_line, local_num_lines);
//getchar();
while (1)
{
while (pthread_mutex_lock(buffer_mutex))
{}
for (i=0; i < MAX_THREAD_COUNT_PER_PROCESS; i++)
{
if (buffer[i].valid == 1)
{
line = buffer[i].line;
k = buffer[i].line_num;
buffer[i].valid = 0;
printf ("Thread %u checking line %u - which is %s \n", local_thread_num, k, buffer[i].line);
break;
}
}
pthread_mutex_unlock(buffer_mutex);
i = 0, j = 0, wordcount_in_line = 0;
while ( (*(line+i) != '\n') )
{
// Extract word
if ( (*(line+i) == ' '))
{
// NUll terminate the word to make it a string
*(word+j) = '\0';
// Compare
//printf ("Thread %u checking line %u - word number %u which is %s \n", local_thread_num, k, wordcount_in_line, word);
if (strcmp (word, local_string_to_search) == 0) // No double quotes around argv[2]
{
count ++;
printf("Thread %u found its local %uth occurence of %s in line %u at word %u \n", local_thread_num, count, word, k, wordcount_in_line);
}
// Make j = -1, after increment it will be 0 for new word
j = -1;
wordcount_in_line++ ;
}
else
{
*(word+j) = *(line+i);
}
// Increment both i and j to go to next character
i++; j++;
}
if ((*(line + i)) == '\n')
{
// If end of line - do the same thing on last word as is for every word
// NUll terminate the word to make it a string
*(word + j) = '\0';
// Compare
//printf ("Thread %u checking line %u - word number %u which is %s \n", local_thread_num, k, wordcount_in_line, word);
if (strcmp(word, local_string_to_search) == 0) // No double quotes around argv[2]
{
count++;
printf("Thread %u found its local %uth occurence of %s in line %u at word %u \n", local_thread_num, count, word, k, wordcount_in_line);
}
wordcount_in_line++ ;
}
}
void* status;
int rc;
rc = pthread_join (threads[0], &status);
printf ("Thread %u found %u occurences \n", local_thread_num, count);
i_pthread_argv->count = count;
//return (count);
pthread_exit(NULL);
}
int main (int argc, char* argv[])
{
// Declare file *
FILE* fp;
// Get file path and open file
//fp = fopen ("file_name.txt","r");
fp = fopen (argv[1],"r"); // No "" around argv[1]
if (fp == NULL)
{
printf ("fopen failed \n");
return 0;
}
printf ("file = %s and string to look for = %s \n", argv[1], argv[2]);
//fopen_s(&fp, "file_name.txt", "r");
//Initialize mutex
if (pthread_mutex_init(buffer_mutex, NULL))
printf ("Mutex initialization failed \n");
// Get number of lines in file
uint num_threads;
sscanf(argv[3], "%u", &num_threads);
// Create threads
//pthread_t* threads;
threads = (pthread_t*) malloc (sizeof (pthread_t)*MAX_THREAD_COUNT_PER_PROCESS);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
uint i = 0;
read_pthread_argv.fp = fp;
if ( pthread_create (&threads[0], &attr , read_file, (void*)(&read_pthread_argv) ) == 0)
printf("Thread creation %u passed \n", i);
for ( i = 1; i<num_threads; i++ )
{
count_pthread_argv[i].thread_num = i;
count_pthread_argv[i].string_to_search = argv[2];
//printf("Reached debugging point 1 \n");
if ( pthread_create (&threads[i], &attr , count_string, (void*)(&count_pthread_argv[i]) ) == 0)
printf("Thread creation %u passed \n", i);
}
//printf("Reached debugging point 2 \n");
// Doubt 2 - How to call pthread_join to wait for completion of multiple threads -
// Isnt the for loop executed sequentially and pthread_join in main for thread-2 will be executed after thread-1 exits
// Wait till all are over
pthread_attr_destroy(&attr);
void* status;
int rc;
for (i = 1; i<num_threads; i++ )
{
rc = pthread_join (threads[i], &status);
}
uint totalcount = 0;
for (i = 1; i<num_threads; i++)
{
printf ("count_returned = %u \n", count_pthread_argv[i].count);
totalcount += count_pthread_argv[i].count;
}
printf("From main, The file has %s -> %u times", argv[2], totalcount);
for (i=0; i<MAX_THREAD_COUNT_PER_PROCESS; i++)
{
free (buffer[i].line);
}
pthread_mutex_destroy(buffer_mutex);
getchar();
pthread_exit(NULL);
}