【问题标题】:Enqueue local stack variable to global List so other thread can consume it将本地堆栈变量排入全局列表,以便其他线程可以使用它
【发布时间】:2015-12-01 12:25:52
【问题描述】:

我有一个带有两个 pthread 的程序。

每个节点上都有一个全局变量List,用于保存(char *)。

在主线程中,我声明、malloc 并初始化一个 (char *) 并将其加入到全局列表中。

第二个线程无限循环等待全局列表中的新节点被消耗。

问题是第二个线程似乎无法使用第一个线程构建的 (char *),因为第一个线程已经返回,所以 (char *) 可能已被释放。

有什么建议吗?

谢谢。

【问题讨论】:

  • 请创建一个 MCVE:stackoverflow.com/help/mcve
  • 你使用的是什么List 实现?
  • 我正在使用这个 List 实现:github.com/SchedMD/slurm/blob/master/src/common/list.c
  • 这个问题是关于运行时问题。因此,干净编译、简短且显示问题的后代码。发布预期和实际产出。发布实际输入。否则我们只能猜测。发布您的代码,而不是其他人代码的链接
  • 该问题表示一个非常简单的问题。引用的代码包含许多不良的编程实践,例如给函数名起别名,通过宏编写函数定义,以及.....您的代码需要做的就是; 1)定义节点 2)声明“头”指针 3)附加节点 4)删除第一个节点 5)检查“头”指针是否包含 NULL(空列表)并用数据“填充”节点。您可能希望使用 `pthread_mutex...() 函数在线程之间进行协调。

标签: c variables scope pthreads


【解决方案1】:

malloc 分配的内存不会在线程结束时自动释放。您还有其他问题。
也许第二个线程在一个紧密的循环中工作,所有访问都转到寄存器而不是内存。

【讨论】:

    【解决方案2】:

    全局变量:

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

    init() 和构建函数(主线程):

    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;
    }
    

    第二个线程等待 List 节点被消耗:

    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);
        }
    

    }

    【讨论】:

    • 为什么要使用extern 修饰符?它们表明该函数在其他地方定义,extern 仅对数据真正有用。函数名称在“链接”时通过“原型”语句而不是“外部”修饰符解析
    • 在函数和变量名称上使用一个或多个前导下划线“几乎”总是一个坏主意,因为编译器会在名称前面加上这样的下划线,这可能会导致编译器混淆
    【解决方案3】:

    发布的代码包含几个问题,比如没有等待线程退出。

    建议以下代码,该代码已在ubuntu linux 14.04上测试并正常运行

    注意 pthread_mutex_lock() 和 pthread_mutex_unlock() 的使用

    注意 pthread_join() 的使用

    一般来说,代码需要写得越简单越好。

    #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
    

    以上代码产生如下输出:

    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
    

    您可以轻松地修改您的特定struct 定义的代码、生成结构实例的方法、在线程中接收到结构时的处理方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-18
      • 2017-08-21
      • 1970-01-01
      • 1970-01-01
      • 2013-06-27
      • 2017-02-16
      • 1970-01-01
      • 2023-04-03
      相关资源
      最近更新 更多