Search code examples
cpthreadspthread-join

using pthread with memory leak


Just a small program to test multi-threading. It supposed to print out a 'Hello' message with the index of the thread and the thread location.

I read why pthread cause memory leak and tried to use pthread_join. It seems that the memory leak still remains

Following is my code:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>

void runMe(int *arg) {
    printf("Hello %d from %x\n", *arg, (unsigned int)pthread_self());
    int *ret = (int*)malloc(sizeof(int));
    *ret = *arg + 4; // note this value '4' will be different in the quiz!

    pthread_exit((void*)ret);
}

int run_threads(int n) {
    pthread_t thr[n];
    int thr_args[n];
    int *ptr = 0;
    int total = 0;

    for (int i=0; i<n; i++) {
        thr_args[i] = i;
        pthread_create(&thr[i], NULL, (void*)runMe, &thr_args[i]);

    }
    for (int j=0; j<n; j++) {
        pthread_join(thr[j], (void*)ptr++);
        total += thr_args[j];
    }
    return total;
}

int main() {

    run_threads(10);

}

Following is the result of running valgrind:

==10292== 
==10292== HEAP SUMMARY:
==10292==     in use at exit: 1,654 bytes in 14 blocks
==10292==   total heap usage: 26 allocs, 12 frees, 5,454 bytes allocated
==10292== 
==10292== LEAK SUMMARY:
==10292==    definitely lost: 40 bytes in 10 blocks
==10292==    indirectly lost: 0 bytes in 0 blocks
==10292==      possibly lost: 0 bytes in 0 blocks
==10292==    still reachable: 1,614 bytes in 4 blocks
==10292==         suppressed: 0 bytes in 0 blocks
==10292== Rerun with --leak-check=full to see details of leaked memory
==10292== 
==10292== For counts of detected and suppressed errors, rerun with: -v
==10292== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Solution

  • Your leak is because the memory you allocate has no corresponding free action.

    The code you're using appears to be trying to convey a dynamic allocation back to the caller. Proper use of pthread_join and its second parameter can recoup that memory pointer, which can then be properly freed.

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    void* runMe(void *pv)
    {
        int *arg = pv;
        printf("Hello %d from %x\n", *arg, (unsigned int)pthread_self());
        int *ret = malloc( sizeof *ret );
        *ret = *arg + 4; // note this value '4' will be different in the quiz!
        return ret;
    }
    
    int run_threads(int n) {
        pthread_t thr[n];
        int thr_args[n];
        int total = 0;
    
        for (int i=0; i<n; i++) {
            thr_args[i] = i;
            pthread_create(thr+i, NULL, runMe, thr_args+i);
    
        }
        for (int j=0; j<n; j++)
        {
            // reap pointer from resulting thread.
            void *res = NULL;
            pthread_join(thr[j], &res);
    
            int *ires = res;
            printf("ires = %p; *ires = %d\n", ires, *ires);
            free(ires);
    
            total += thr_args[j];
        }
        return total;
    }
    
    int main()
    {
        run_threads(10);
    }
    

    Output (varies)

    Hello 9 from b0a71000
    Hello 0 from b05df000
    Hello 7 from b096d000
    Hello 2 from b06e3000
    Hello 1 from b0661000
    Hello 4 from b07e7000
    Hello 3 from b0765000
    Hello 5 from b0869000
    Hello 6 from b08eb000
    Hello 8 from b09ef000
    ires = 0x600000; *ires = 4
    ires = 0x2009e0; *ires = 5
    ires = 0x600010; *ires = 6
    ires = 0x500010; *ires = 7
    ires = 0x2009f0; *ires = 8
    ires = 0x2012c0; *ires = 9
    ires = 0x600020; *ires = 10
    ires = 0x400040; *ires = 11
    ires = 0x400050; *ires = 12
    ires = 0x500000; *ires = 13
    

    I also took liberty to fix your incorrect, non-compliant function signature you were using. pthread_create requires the form:

    void *proc(void *)
    

    for the thread procedure. Anything not of that form isn't compliant, and should be avoided.