lizhenneng 发表于 2013-05-20 23:10

pthread_join后释放资源报错

写了两段代码,第一段是man pthread_join的例子,可正常释放pthread_join返回的res,
另一段代码类似,不过在释放由pthread_join返回的指针free(res)时出现的堆多次释放的问题,不知为何,代码如下:

运行正常代码(可通过man pthread_join看到或者见附件):
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>

#define handle_error_en(en, msg) \
        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
       
#define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)
       
struct thread_info {                        /* Used as argument to thread_start() */
        pthread_t        thread_id;                /* ID returned by pthread_create() */
        int                        thread_num;                /* Application-defined thread # */
        char            *argv_string;        /* From command-line argument */
};

/* Thread start function: display address near top of our stack,
   and return upper-cased copy of argv_string */

static void *
thread_start(void *arg)
{
        struct thread_info *tinfo = (struct thread_info *) arg;
        char *uargv, *p;
       
        printf("Thread %d: top of stack near %p; argv_string=%s\n",
                        tinfo->thread_num, &p, tinfo->argv_string);
       
        uargv = strdup(tinfo->argv_string);
        if (uargv == NULL)
                handle_error("strdup");
       
        for (p = uargv; *p != '\0'; p++)
                *p = toupper(*p);
       
        return uargv;
}

int
main(int argc, char *argv[])
{
        int s, tnum, opt, num_threads;
        struct thread_info *tinfo;
        pthread_attr_t attr;
        int stack_size;
        void *res;

        /* The "-s" option specifies a stack size for our threads */
       
        stack_size = -1;
        while ((opt = getopt(argc, argv, "s:")) != -1) {
                switch (opt) {
                case 's':
                        printf("optarg: %s\n", optarg);
                        stack_size = strtoul(optarg, NULL, 0);
                        break;
       
                default:
                        fprintf(stderr, "Usage: %s [-s stack-size] arg ... \n", argv);
                        exit(EXIT_FAILURE);
                }
        }
       
        num_threads = argc - optind;
        /* Initialize thread creation attributes */
       
        s = pthread_attr_init(&attr);
        if (s != 0)
                handle_error_en(s, "pthread_attr_init");
       
        if (stack_size > 0) {
                s = pthread_attr_setstacksize(&attr, stack_size);
                if (s != 0)
                        handle_error_en(s, "pthread_attr_setstacksize");
        }

        /* Allocate memory for pthread_create() arguments */
       
        tinfo = calloc(num_threads, sizeof(struct thread_info));
        if (tinfo == NULL)
                handle_error("calloc");
               
        /* Create one thead for each command-line argument */

        for (tnum = 0; tnum < num_threads; tnum++) {
                tinfo.thread_num = tnum + 1;
                tinfo.argv_string = argv;
               
                /* The pthread_create() call stores the thread ID into corresponding element of tinfo[] */

                s = pthread_create(&tinfo.thread_id, &attr,
                                                        &thread_start, &tinfo);
       
                if (0 != s)
                        handle_error_en(s, "pthread_create");
        }
       
        /* Destroy the thread attributes object, since it is no longer needed */
       
        s = pthread_attr_destroy(&attr);
        if (0 != s)
                handle_error_en(s, "pthread_attr_destroy");
               
        /* Now join with each thread, and display its returned value */
       
        for (tnum = 0; tnum < num_threads; tnum++) {
                s = pthread_join(tinfo.thread_id, &res);
                if (0 != s)
                        handle_error_en(s, "pthread_join");
       
                printf("Joined with thread %d; returned value was %s\n",
                                tinfo.thread_num, (char *) res);
                free(res);        /* Free memory allocated by thread */
        }
       
        free(tinfo);
        exit(EXIT_SUCCESS);
}


运行异常代码(可下载附件源码):
/*
* used syscall:
* pthread_key_create;
* pthread_once;
* pthread_getspecific;
* pthread_setspecific;
*/

#include <limits.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

#define ARG_MAX                                1000
#define THREADS_NUM                 1
#define THREAD_STACK_SIZE        0x100000
#define handle_error_en(en, msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)

#define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)

static pthread_key_t key;
static pthread_once_t init_done = PTHREAD_ONCE_INIT;
pthread_mutex_t env_mutex = PTHREAD_MUTEX_INITIALIZER;

extern char **environ;

struct thread_info {
        pthread_t        thread_id;
        int                        thread_num;
        char                 *argv_string;
};

static void
thread_init(void)
{
        pthread_key_create(&key, free);
}

char *
getenv(const char *name)
{
        int                i, len;
        char         *envbuf;

        pthread_once(&init_done, thread_init);
        pthread_mutex_lock(&env_mutex);
        envbuf = (char *)pthread_getspecific(key);
        if (NULL == envbuf) {
                envbuf = malloc(ARG_MAX);
                if (NULL == envbuf) {
                        pthread_mutex_unlock(&env_mutex);
                        return (NULL);
                }
                pthread_setspecific(key, envbuf);
        }
        len = strlen(name);
        for (i = 0; environ != NULL; i++) {
                if ((strncmp(name, environ, len) == 0) &&
                        (environ == '=')) {
                                strcpy(envbuf, &environ);
                                pthread_mutex_unlock(&env_mutex);
                                return (envbuf);
                }
        }
        pthread_mutex_unlock(&env_mutex);
        return (NULL);
}

void *
fn(void *arg)
{
        return getenv((const char *)arg);
}

int
main(int argc, char *argv[])
{
        int tnum, err;
        pthread_t tid;       
        struct thread_info *tinfo;
        void *res;
        pthread_attr_t attr;
        char name[] = "PATH";

        err = pthread_attr_init(&attr);
        if (0 != err)
                handle_error_en(err, "pthread_attr_init");
               
        if (THREAD_STACK_SIZE > 0) {
                err = pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);
                if (0 != err)
                        handle_error_en(err, "pthread_attr_setstacksize");
        }

        tinfo = calloc(THREADS_NUM, sizeof(struct thread_info));
        if (NULL == tinfo)
                handle_error("calloc");
        for (tnum = 0; tnum < THREADS_NUM; tnum++)
        {
                tinfo.thread_num = tnum + 1;
                tinfo.argv_string = "test";
       
                err = pthread_create(&tinfo.thread_id, &attr,
                                                        fn, (void *)name);
                if ( 0 != err)
                        handle_error_en(err, "pthread_create");
        }
       
        err = pthread_attr_destroy(&attr);
        if (0 != err)
                handle_error_en(err, "pthread_attr_destroy");       

        for (tnum = 0; tnum < THREADS_NUM; tnum++) {
                err = pthread_join(tinfo.thread_id, &res);
                if (0 != err)
                        handle_error_en(s, "pthread_join");
               
                printf("Joined with thread %d; returned value was %s\n",
                                tinfo.thread_num, (char *) res);
                free(res);
        }
               
        free(tinfo);
        exit(EXIT_SUCCESS);
}

lizhenneng 发表于 2013-05-22 20:50

自己顶一个

lizhenneng 发表于 2013-05-26 21:11

自已再顶一个,希望有好心人解答!

lizhenneng 发表于 2013-06-03 23:13

还是没人回啊

井蛙夏虫 发表于 2013-06-04 12:27

本帖最后由 井蛙夏虫 于 2013-06-04 12:27 编辑

回复 4# lizhenneng
对于pthread_key_create:An optional destructor function may be associated with each key value.At thread exit, if a key value has a non-NULL destructor pointer, and the thread has a non-NULL valueassociatedwiththat key,the value of the key is set to NULL, and then the function pointed to is called with the previously associated value as its sole argument.所以在你调用pthread_join后,线程局部存储已经被释放,你不应当再次调用free来释放。pthread_join后的printf引用指向线程局部存储的res变量也是不合法的。
你可以将pthread_key_create调用的free参数换为NULL试试。
页: [1]
查看完整版本: pthread_join后释放资源报错