Thread: Linux Mulithreaded Program - Help please!

  1. #1
    Registered User
    Join Date
    Sep 2013
    Posts
    12

    Exclamation Linux Mulithreaded Program - Help please!

    Hello all,

    I am new to multithreaded programming (in the Linux Debian environment) and so I thought I would work on a project to help me learn it. Here are the details of the project:

    Write a multithreaded sorting program that works as follows: A list of integers is divided into two smaller lists of equal size. Two separate threads (which we will term sorting threads) sort each sublist using a sorting algorithm of your choice. The two sublists are then merged by a third thread - a merging thread - which merges the two sublists into a single sorted list.

    I understand the general outline of what I'm supposed to do. Here's my code of what I've done so far (For the sorting algorithm I thought it might be best to implement a bubble sort):

    Code:
    #include <pthread.h>
    #include <stdio.h>
    #include  <stdlib.h>
    #include <sys/types.h>
    
    #define SIZE 10
    
    //three threads
    void *sorter(void *params);
    void *merger(void *params);
    
    int list[SIZE] = {7,12, 19, 3, 18, 4, 2,6, 15, 8};
    
    int result[SIZE];
    
    typedef struct
    {
        int from_index;
        int to_index;
    } parameters;
    
    int main(int argc, char *argv[]){
    
        pthread_t pid1, pid2, pid3;
        
        //establish the first sorting thread
        parameters *data = (parameters *) malloc(sizeof(parameters));
        
        data->from_index = 0;
        data->to_index = (SIZE/2)-1;
        pthread_create(&pid1, 0, sorter, data);
        
        //establish second sorting thread
        data->from_index = (SIZE/2);
        data->to_index = SIZE-1;
        pthread_create(&pid2,0, sorter, data);
        
        pthread_join(pid1,NULL);
        pthread_join(pid2,NULL);
        
        //create merge thread
        data = (parameters *) malloc(sizeof(parameters));
        data->from_index = 0;
        data->to_index = (SIZE/2);
        pthread_create(&pid3, 0, merger, data);
        
        pthread_join(pid3,NULL);
        
        //print the result array
        
        return 0;
        
    }
    
    void *sorter(void *params){
    
    parameters* p = (parameters*) params;
    
    int begin = p->from_index;
    int end = p->to_index;
    
    //sort
    int i,j,t;
    
    for(i=begin; i< end; i++)
    {
        for(j=begin; j< end-i; j++)
        {
    
            if(list[j] > list[j+1])
            {
                t = list[j];
                list[j] = list[j+1];
                list[j+1] = t;
                list[j] = result[j];
            }
        }
    }
    
    
    printf("Sorted array is: ");
    int k;
    for(k = begin; k< end+1; k++)
    {
        printf(result[k]);
    }
    
    }
    
    void *merger(void *params){
    
    parameters* p = (parameters*) params;
    
    int begin = p->from_index;
    int end = p->to_index;
    
    //sort
    int i,j,t;
    
    for(i=begin; i< end; i++)
    {
        for(j=begin; j< end-i; j++)
        {
    
            if(list[j] > list[j+1])
            {
                t = list[j];
                list[j] = list[j+1];
                list[j+1] = t;
                list[j] = result[j];
            }
        }
    }
    
    
    
    int k;
    for(k = begin; k< end+1; k++)
    {
        printf("The result is: ", result[k]);
    
    }
    }
    This is as far as I've gotten. I'm kinda stuck on what to do. I know I don't have it quite right. Would anyone be able to help me fix this? Thanks in advance for all your help! I really appreciate it!!!

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    My suggestion would be that you get 'sort' and 'merge' working in a straight forward sequential program before trying to use threads.

    FWIW, your use of threads is better than your attempt at merging.

    Done well, a merge should be a single pass through the two arrays.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    You can't pass the same "data" to each sorter thread like that. Give them each their own. Wouldn't be hard to free that memory instead of leaking it.

    +1 on Salem's suggestion. Call sorter(), sorter(), merger() sequentially form main to ensure your algorithm is correct.

    gg

  4. #4
    Registered User
    Join Date
    Sep 2013
    Posts
    12
    Is my sorting and merging algorithm correct at all?
    I thought the sorting algorithm was correct. If it was, how do I use what I have to do the merger?

  5. #5
    Registered User
    Join Date
    Sep 2013
    Posts
    12
    Okay, I've been working on it some more and I've got it down to this

    Code:
    //Sort a list of numbers using two separate threads
    //by sorting half of each list separately then
    //recombining the lists
    
    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #define SIZE 10
    #define NUMBER_OF_THREADS 3
    
    void *sorter(void *params);    /* thread that performs basic sorting algorithm */
    void *merger(void *params);    /* thread that performs merging of results */
    
    int list[SIZE] = {7,12,19,3,18,4,2,6,15,8};
    
    int result[SIZE];
    
    typedef struct
    {
        int from_index;
        int to_index;
    } parameters;
    
    int main (int argc, const char * argv[]) 
    {
        int i;
        
        pthread_t workers[NUMBER_OF_THREADS];
        
        /* establish the first sorting thread */
        parameters *data = (parameters *) malloc (sizeof(parameters));
        data->from_index = 0;
        data->to_index = (SIZE/2) - 1;
        pthread_create(&workers[0], 0, sorter, data);
        
        /* establish the second sorting thread */
        data = (parameters *) malloc (sizeof(parameters));
        data->from_index = (SIZE/2);
        data->to_index = SIZE - 1;
        pthread_create(&workers[1], 0, sorter, data);
        
        /* now wait for the 2 sorting threads to finish */
        for (i = 0; i < NUMBER_OF_THREADS - 1; i++)
            pthread_join(workers[i], NULL);
        
        /* establish the merge thread */
        data = (parameters *) malloc(sizeof(parameters));
        data->from_index = 0;
        data->to_index = (SIZE/2);
        pthread_create(&workers[2], 0, merger, data);
        
        /* wait for the merge thread to finish */
        pthread_join(workers[2], NULL);
        
    
        /* output the sorted array */
        
        return 0;
    }
    
    void *sorter(void *params)
    {
        parameters* p = (parameters *)params;
    
        //SORT
    
        int begin = p->from_index;
        int end = p->to_index+1;
    
        int z;
        for(z = begin; z < end; z++){
        printf("The array recieved is: %d\n", list[z]);
        }
        
        printf("\n");
    
        int i,j,t,k;
    
    for(i=begin; i< end; i++)
    {
        for(j=begin; j< end-i-1; j++)
        {
    
            if(list[j] > list[j+1])
            {
                t = list[j];
                list[j] = list[j+1];
                list[j+1] = t;
                
            }
        }
    }
    
    for(k = begin; k< end; k++){
        printf("The sorted array: %d\n", list[k]);
    }
    
    int x;
    for(x=begin; x<end; x++)
    {
    list[x] = result[x];
    }
    
    printf("\n");
    
        pthread_exit(0);
    }
    
    void *merger(void *params)
    {
        parameters* p = (parameters *)params;
        
        //MERGE
        int begin = p->from_index;
        int end = p->to_index+1;
    
    int i,j,t;
    
    printf("list[1]: %d",list[1]);
    printf("result[1]: %d",result[1]);
    
    for(i=begin; i< end; i++)
    {
        for(j=begin; j< end-i; j++)
        {
    
            if(result[j] > result[j+1])
            {
                t = result[j];
                result[j] = result[j+1];
                result[j+1] = t;
                
            }
        }
    }
    
    int d;
    for(d=0; d<SIZE; d++)
    {
        printf("The final resulting array is: %d\n", result[d]);
    }
            
        pthread_exit(0);
    }
    I'm still not sure what I'm doing wrong in my algorithms that its not working. It doesn't seem to catch the new sorted array. Any help on this problem would be appreciated VERY much! Thanks again in advance for all your help!

  6. #6
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Follow Salem's advice and test your sort in a separate program without threads. Does it work correctly?


    Do the same for an actual merge algorithm. (Presently it's just a copy of your sort algorithm.)


    Only when those are working should you try to put them together.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  7. #7
    Registered User
    Join Date
    Sep 2013
    Posts
    12
    I know the sorting method works. I've tested it and it runs like its supposed to. What I'm trying to do in the program is take the elements of list, sort them and return them to their respective spots. That will be done for both arrays. After each sort, the elements will be copied over into the same respective positions of the result array in which will be passed to the merge method where I sort the result. Maybe this is not the correct way of doing it or performing such a merger? Any help would be greatly appreciated!

  8. #8
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    > I'm still not sure what I'm doing wrong in my algorithms that its not working. It doesn't seem to catch the new sorted array. Any help on this problem would be appreciated VERY much! Thanks again in advance for all your help!
    Well, for starters, you're not taking people's advice. Salem said (and Codeplug seconded) you call sorter and merger in main without using threads. Tell me, where is our motivation to help you if you don't listen to our advice?

    I would bet money that you decided to write a threaded sort program, and wrote 145 lines without testing. That's the wrong way to do it. Work on one thing at a time. Write 5-10 lines, compile at the maximum warning level, fix all errors and warnings, then test it to make sure the logic works.

    Start from scratch. Get the following working (in roughly this order):
    1. A print function that prints an array of specified length. This will be useful for testing your sort and merge functions.
    Code:
    void print_array(int array[], int len)
    2. A sort function that sorts an array of specified length:
    Code:
    void sort_array(int array[], int len)
    3. A merge function that takes two arrays, each with their own length, and a destination array:
    Code:
    void merge_arrays(int dest[], int src1[], int src1_len, int src2[], int src2_len)
    Make sure you test your sort and merge well.

    Test your sort with already-sorted data, reverse-sorted, all the same number and random data, and any other useful cases you can think of.

    Test your merge with all of src1 before src2 and vice-versa. Test where the merge will have to interleave src1 and src2 elements, ensuring you test cases where src1 comes first and where src2 comes first, as well as where each source array provides the last element. Make sure you test that it handles multiple elements in a row coming from the same source array correctly too. Make sure you do all of those tests with src1 and src2 of the same length, as well as src1 being longer than src2 and vice-versa. Note, this does not mean you have to come up with separate test data for every single case:
    Code:
    #define SHORT_TEST_LEN   3  // define a LONG array length too
    
    int dest[LONG_TEST_LEN * 2];
    int a[SHORT_TEST_LEN] = {1, 2, 3};
    int b[SHORT_TEST_LEN] = {4, 5, 6};
    
    merge(dest, a, SHORT_TEST_LEN, b, SHORT_TEST_LEN);  // tests all of src1 elements before all of src2
    print_array(dest, SHORT_TEST_LEN * 2);
    // reuse a and b, but in the reverse order in the call
    merge(dest, b, SHORT_TEST_LEN, a, SHORT_TEST_LEN);  // tests all of src2 elements before all of src1
    print_array(dest, SHORT_TEST_LEN * 2);
    This seems like a giant pain, but believe me, a good development process with lots of testing saves tons of time. Actually, I'm quite sure you would have this finished by now if you would have followed such a process from the start. Small, incremental changes with lots of testing helps you narrow down the problem easily, making debugging relatively quick and painless. Also, this helps you keep your code modular and loosely-coupled (it would be hard to unit test otherwise), which is just plain good design.

    EDIT: Yes, I know your current sort function works, but it's hard to test well, since it operates on a global variable and it tightly-coupled with the pthread library. Get it working as a standalone array sort funciton, as I suggested. When the time comes to add threading, your thread function will take the parameters and call sort_array with the appropriate part of the array and appropriate length.
    Last edited by anduril462; 10-22-2013 at 08:41 PM.

  9. #9
    Registered User
    Join Date
    Sep 2013
    Posts
    12
    Thank you anduril462 - I appreciate your help. However, I did try and take the advice of you and Salem when I wrote the program. I'll admit, initially I started out by writing a bunch of code and hoping for the best, but when it failed and asked for help from the users here, I broke it down. In a threadless environment, my methods work fine. However, I think I'm doing something wrong with the threads that its not working properly. The other thing is your code suggests that I make two separate arrays from the first. However, I don't see how I can do that. The program starts off with one array. So when I get to the sort method, how do I know that I can put my values in a particular array. What I mean (hopefully more clearly) is that how do I tell the values (whether it be the first pass or second pass into the thread) to go into a particular array? My merge method would be much better if I have multiple arrays to work with, however, It seems feasible to only have two - an initial array (list) and the final, sorted array (result).

    Thanks again for your help!

  10. #10
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Quote Originally Posted by billyjthorton View Post
    Thank you anduril462 - I appreciate your help. However, I did try and take the advice of you and Salem when I wrote the program. I'll admit, initially I started out by writing a bunch of code and hoping for the best, but when it failed and asked for help from the users here, I broke it down. In a threadless environment, my methods work fine.
    You're obviously not listening to people here. I told you that your merge routine is wrong. It's a copy of your sort routine, so how can it work as a merge? A merge is not a sort.

    As for passing two "separate arrays", that's not necessary. An array becomes a pointer to its first element when passed to a function (and most other expression contexts), so you can pass it like this:
    Code:
    sort(list, SIZE/2);
    sort(list+SIZE/2, SIZE-SIZE/2);
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  11. #11
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by billyjthorton View Post
    In a threadless environment, my methods work fine.
    Sorry, but they don't. In post #5, sorter() and merger() as whole functions are both broken. You do correctly sort, but then you ruin your sorted list. merger() doesn't actually merge the two halves, it attempts to sort (incorrectly) the array you give it
    Quote Originally Posted by billyjthorton View Post
    However, I think I'm doing something wrong with the threads that its not working properly.
    Yes, you have a few things wrong with your threaded code. But that will be dealt with later.
    Quote Originally Posted by billyjthorton View Post
    The other thing is your code suggests that I make two separate arrays from the first. However, I don't see how I can do that. The program starts off with one array. So when I get to the sort method, how do I know that I can put my values in a particular array. What I mean (hopefully more clearly) is that how do I tell the values (whether it be the first pass or second pass into the thread) to go into a particular array? My merge method would be much better if I have multiple arrays to work with, however, It seems feasible to only have two - an initial array (list) and the final, sorted array (result).
    My functions will work with partial arrays. You see, for all intents and purposes, there is no difference between two halves of one array, and two separate arrays that are adjacent in memory. That is part of the reason I use length parameters everywhere. So, you can call my sort_array function on two halves, like so:
    Code:
    int list[SIZE] = {7, 12, 19, 3, 18, 4, 2, 6, 15, 8};
    int results[SIZE];
    
    int first_size = SIZE / 2;
    int second_size = SIZE - first_size;
    sort_array(list, first_size);  // sort the first half of the array
    sort_array(list + first_size + 1, second_size);  // sort the second half of the array
    merge_arrays(results, list, first_size, list + first_size + 1, second_size);
    Note, you could write the merge_arrays function to merge in place, but that is a bit tougher. Merging into a separate array is pretty easy.

  12. #12
    Registered User
    Join Date
    Sep 2013
    Posts
    12
    Okay. Its making more sense now...

    anduril462, you say
    You do correctly sort, but then you ruin your sorted list
    Do you think you could point out to me where after the sort I ruin it so I can fix that problem?

  13. #13
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by billyjthorton View Post
    Okay. Its making more sense now...

    anduril462, you say
    Do you think you could point out to me where after the sort I ruin it so I can fix that problem?
    You probably think you're moving entries into your result list, but.....

  14. #14
    Registered User
    Join Date
    Sep 2013
    Posts
    12
    That's one problem I couldn't figure out...why won't the entries go into the global variables?

  15. #15
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by billyjthorton View Post
    That's one problem I couldn't figure out...why won't the entries go into the global variables?
    Well, what's the difference between
    Code:
    a = b;
    and
    Code:
    b = a;
    ?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How to Linux Program
    By lruc in forum Linux Programming
    Replies: 20
    Last Post: 08-25-2008, 06:59 PM
  2. Best way to program on Linux?
    By dweenigma in forum Tech Board
    Replies: 22
    Last Post: 05-14-2007, 05:20 AM
  3. Can't compile an SDL program under Linux
    By dwks in forum Game Programming
    Replies: 2
    Last Post: 01-16-2006, 08:51 PM
  4. calendar program for linux
    By *ClownPimp* in forum Tech Board
    Replies: 1
    Last Post: 10-01-2005, 02:31 AM
  5. How can I debug a program in linux?
    By zahid in forum C Programming
    Replies: 5
    Last Post: 12-11-2001, 10:34 PM

Tags for this Thread