3

twalk()を使用して二分木をトラバースしようとしています<search.h>

   #define _GNU_SOURCE     /* Expose declaration of tdestroy() */
   #include <search.h>
   #include <stdlib.h>
   #include <stdio.h>
   #include <time.h>

   void *root = NULL;

   void *
   xmalloc(unsigned n)
   {
       void *p;
       p = malloc(n);
       if (p)
           return p;
       fprintf(stderr, "insufficient memory\n");
       exit(EXIT_FAILURE);
   }

   int
   compare(const void *pa, const void *pb)
   {
       if (*(int *) pa < *(int *) pb)
           return -1;
       if (*(int *) pa > *(int *) pb)
           return 1;

       return 0;
   }

   void
   action(const void *nodep, const VISIT which, const int depth)
   {
       int *datap;

       switch (which) {
       case preorder:
           break;
       case postorder:
           datap = *(int **) nodep;
           printf("%6d\n", *datap);
           break;
       case endorder:
           break;
       case leaf:
           datap = *(int **) nodep;
           printf("%6d\n", *datap);
           break;
       }
   }

   int
   main(void)
   {
       int i, *ptr;
       void *val;

       srand(time(NULL));
       for (i = 0; i < 12; i++) {
           ptr = (int *) xmalloc(sizeof(int));
           *ptr = rand() & 0xff;
           val = tsearch((void *) ptr, &root, compare);
           if (val == NULL)
               exit(EXIT_FAILURE);
           else if ((*(int **) val) != ptr)
               free(ptr);
       }
       twalk(root, action);
       tdestroy(root, free);
       exit(EXIT_SUCCESS);
   }

ご覧のとおり、action()に変数を渡したり、action()から変数を返したりする方法はありません。なぜそんなに気密なのですか?プログラムがスレッドを使用しているため、グローバルを使用できません。私の質問は、スレッドセーフモードでトラバース(および非グローバル変数とnodepを共有)するにはどうすればよいですか?すみません、私の貧弱な英語

編集: アンワインドが言ったように、解決策はこの特定のホイールを再発明し、tsearch.cで使用される構造を再定義することで問題を解決します:

/* twalk() fake */

struct node_t
{
    const void *key;
    struct node_t *left;
    struct node_t *right;
    unsigned int red:1;
};

static void tmycallback(const xdata *data, const void *misc)
{
    printf("%s %s\n", (const char *)misc, data->value);
}

static void tmywalk(const struct node_t *root, void (*callback)(const xdata *, const void *), const void *misc)
{
    if (root->left == NULL && root->right == NULL) {
        callback(*(xdata * const *)root, misc);
    } else {
        if (root->left != NULL) tmywalk(root->left, callback, misc);
        callback(*(xdata * const *)root, misc);
        if (root->right != NULL) tmywalk(root->right, callback, misc);
    }
}

/* END twalk() fake */

if (root) tmywalk(root, tmycallback, "Hello walker");
4

2 に答える 2

4

関数を指定して実装した人を除いて、誰も「なぜ」に正確に答えることはできないと思います。私は「近視眼的」、あるいは「歴史的理由」(スレッドプログラミングが一般的になる前にそれを行った)を推測します。

とにかく、このAPIは、この制限のために私には少し「おもちゃ」のように見えます。実際、void *APIとコールバックの間で不透明に渡されるユーザー所有のAPIを含めることができないすべてのAPIも同様です。

したがって、私が推測する解決策は、この特定のホイールを再発明し、バイナリツリーをトラバースするための独自の関数を作成することです。

于 2012-11-21T09:26:57.607 に答える
1

スレッドローカルストレージを使用して、グローバル変数を使用しながらスレッドセーフにすることができます。どうやらあなたは__threadこの目的のためにキーワードを使うことができます。c99での__threadの使用も確認してください。

于 2012-11-21T09:37:49.337 に答える