我的多线程代码给出了错误的结果并且存在分段错误

时间:2019-04-30 01:01:06

标签: c multithreading pthreads

我有一个程序,必须在命令行上使用file_name,字符串string_name(单词)和整数(线程数)作为参数。然后程序创建了这么多线程来计算string_name在文件-file_name中出现的次数。

串行代码正常运行。 多线程代码存在以下问题:

  1. 这会导致核心转储-分段错误。
  2. 计数错误。

我添加了一些调试语句:

  1. 它显示错误的行号,我试图打印哪个线程号检查哪个行号。
#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);
}


0 个答案:

没有答案