0
votes

I have a program with two pthreads.

There is a global variable List for holding (char *) on each node.

In the main thread, I declare, malloc and initialize a (char *) and enqueue it to the global List.

The second thread is waiting in an infinite loop for new nodes in the global List to be consumed.

The problem is that the second thread seems to not be able to consume the (char *) built by the first thread, because the first thread has already returned and so the (char *) probably has been freed.

Any suggestions?

Thank you.

3
Please create an MCVE: stackoverflow.com/help/mcve - Shloim
What List implementation are you using? - John Zwinck
I'm using this List implementation: github.com/SchedMD/slurm/blob/master/src/common/list.c - alex
This question is about a run time problem. Therefore, post code that cleanly compiles, is short, and exhibits the problem. Post expected and actual outputs. Post the actual input. Otherwise all we can do is guess. Post your code, not some link to someone elses' code - user3629249
The question indicates a very simple problem. The referenced code contains many bad programming practices, like aliasing the function names, and writing function definitions via macros, and ..... All your code needs to do is; 1) define the node 2) declare the 'head' pointer 3) append a node 4) remove first node 5) check if 'head' pointer contains NULL (empty list) and 'populate' a node with data. You may want to use the `pthread_mutex...() functions for coordination between threads. - user3629249

3 Answers

1
votes

The memory allocated by malloc is not freed automatically when a thread end. You have some other issue.
Maybe the second thread is working in a tight loop and all accesses go to registers and not the memory.

0
votes

Global variables:

...
static pthread_t job_handler_thread;
List jobslist = NULL;
...

init() and build function (main thread):

extern int init(void)
{
    int rc;

    jobslist = list_create(NULL);
    pthread_attr_t thread_attr;
    slurm_attr_init(&thread_attr);
    if (pthread_create(&job_handler_thread, &thread_attr,
                       _process_jobs, NULL))
            fatal("pthread_create error %m");
    slurm_mutex_lock(&pend_jobs_lock);
    rc = _load_pending_jobs();
    slurm_mutex_unlock(&pend_jobs_lock);

    return rc;
}

extern int slurm_jobcomp_log_record(struct job_record *job_ptr)
{
    char *json_job;
    int rc = SLURM_SUCCESS;

    // pass char * by reference. Inside the function
    // memory is allocated for the char *
    rc = _job_serialize(job_ptr, &json_job);

    if (rc == SLURM_SUCCESS)
            list_enqueue(jobslist, json_job);

    return rc;
}

Second thread waiting for List nodes to be consumed:

extern void* _process_jobs()
{
    char *json_job;

    while(1)
    {
            if (list_is_empty(jobslist)) {
                    sleep(1);
                    continue;
            }
            json_job = list_dequeue(jobslist);
            // At this point I should process json_job
            // But data is not available here
            printf("%s", json_job);
    }

}

0
votes

the posted code contains several problems, like not waiting for the thread to exit.

Suggest the following code, which has been tested and works correctly on ubuntu linux 14.04

Notice the use of pthread_mutex_lock() and pthread_mutex_unlock()

Notice the use of pthread_join()

In general, code needs to be written as simply as possible, but no simpler.

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

#define MAX_JOBS     (25)
#define MAX_DATA_LEN (25)

struct node
{
    int last;
    char data[MAX_DATA_LEN];
    struct node *next;
};


static pthread_t       thread_id;
static struct node    *jobsList = NULL;
static pthread_mutex_t jobsMutex =  PTHREAD_MUTEX_INITIALIZER;

void         putNode( struct node * newNode );
struct node *getNode( void );
struct node *createNode( void );

void* process_job( void* );


int main( void )
{
    if( 0 != pthread_create( &thread_id, NULL, process_job, NULL) )
    {
        perror( "pthread_create failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, pthread_create successful

    int done = 0;
    while( !done )
    {
        struct node *newNode = NULL;
        if( NULL  == (newNode = createNode() ) )
        {
            done = 1;
        }

        else
        {
            putNode( newNode );
        }
    }

    pthread_join( thread_id, NULL);
    pthread_mutex_destroy( &jobsMutex );
    return 0;
} // end function: main


struct node* createNode()
{
    static  char dataCount = 0;
    char         data[ MAX_DATA_LEN ] = {'\0'};
    struct node *newNode = NULL;

    if( MAX_JOBS > dataCount )
    {
        if( NULL != (newNode = malloc( sizeof( struct node ) ) ) )
        {
            newNode->last = ( dataCount < (MAX_JOBS-1) )? 0 : 1;
            dataCount++;
            newNode->next = NULL;

            sprintf( data, "%s %d", "this is node: ", dataCount );
            strcpy( newNode->data, data );
        }
    }

    return newNode;
} // end function: createNode


void putNode( struct node *newNode )
{
    struct node *current = NULL;

    pthread_mutex_lock( &jobsMutex );

    if( !jobsList)
    {
        jobsList = newNode;
    }

    else
    {
        for( current = jobsList; current->next; current = current->next);

        current->next = newNode;
    }

    pthread_mutex_unlock( &jobsMutex );
} // end function: putNode


// the thread process
void *process_job( void *parm )
{
    (void) parm;
    struct node * newNode;

    int done = 0;
    while( !done )
    {
        while(1)
        {
            if(NULL == (newNode = getNode() ) )
            {
                sleep(1);
            }

            else
            {
                break;
            }
        }

        printf( "newNode data: %s\n", newNode->data);
        free( newNode );
        if( newNode->last ) done = 1;
    }

    pthread_exit( 0 );
} // end function: process_job


struct node *getNode()
{
    pthread_mutex_lock( &jobsMutex );
    if( !jobsList )
    {
        pthread_mutex_unlock( &jobsMutex );
        return NULL;
    }

    struct node *current = NULL;

    current = jobsList;
    jobsList = jobsList->next;

    pthread_mutex_unlock( &jobsMutex );
    return current;
} // end function: getNode

The above code results in the following output:

newNode data: this is node:  1
newNode data: this is node:  2
newNode data: this is node:  3
newNode data: this is node:  4
newNode data: this is node:  5
newNode data: this is node:  6
newNode data: this is node:  7
newNode data: this is node:  8
newNode data: this is node:  9
newNode data: this is node:  10
newNode data: this is node:  11
newNode data: this is node:  12
newNode data: this is node:  13
newNode data: this is node:  14
newNode data: this is node:  15
newNode data: this is node:  16
newNode data: this is node:  17
newNode data: this is node:  18
newNode data: this is node:  19
newNode data: this is node:  20
newNode data: this is node:  21
newNode data: this is node:  22
newNode data: this is node:  23
newNode data: this is node:  24
newNode data: this is node:  25

You can easily modify the code for your specific struct definition, method of generating struct instances, method of processing the struct when received in the thread.