2

pthread.h をオーバーライドしてユーザー レベルのスレッド ライブラリを作成する C のプロジェクトに取り組んでいます。私は現在、ミューテックス機能に取り組んでいます。

私の実装では、ミューテックスを構造体のリンクされたリストとして保存します。pthread_mutex_init でやりたいことは、新しく作成されたミューテックスである要素へのポインターを pthread_mutex_t ミューテックス変数に格納することです。しかし、これは可能ですか?ここに私のコードの一部を示します。これで、私が何をしようとしているのかがわかります。

typedef struct mutexList
{
    int mid;
    struct mutexList *prevMutex;
    struct mutexList *nextMutex;
    int locked;
    struct queueItem *owner;
    struct blockedThread *blockedHead;
    struct blockedThread *blockedTail;
} mutexElement;

int mutexCounter = 0;

mutexElement *mutexHead = NULL;
mutexElement *mutexTail = NULL;

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
{
    mutexElement *newMutex = (mutexElement *) malloc(sizeof(mutexElement));

    fprintf(stdout, "***LOG: Creating new mutex.\n");

    if(newMutex == NULL)
        return ENOMEM;
    newMutex->mid = mutexCounter;
    mutexCounter++;
    newMutex->locked = 0;
    newMutex->nextMutex = NULL;
    newMutex->blockedHead = NULL;
    newMutex->blockedTail = NULL;

    if(mutexHead == NULL)
        mutexHead = newMutex;

    if(mutexTail != NULL)
        mutexTail->nextMutex = newMutex;

    mutexTail = newMutex;

    mutex = (&newMutex);

    return 0;
}
4

2 に答える 2

2

あなたの一般的なアイデアはうまくいくと思いますが、あなたの特定の例には少なくともいくつかの問題があります。

  • your mutexCountermutexHeadおよびmutexTailアイテムはスレッドセーフな方法で処理されません (この種のライブラリの重要なプロパティ)
  • mutex = (&newMutex);は無意味です -mutexユーザーの引数のコピーであるパラメーターです。関数が戻ると、mutex単に存在しなくなります。呼び出し元には返されません。
  • &newMutexそもそもユーザーに戻ろうとしても問題newMutexです。関数が戻ると期限切れになるローカル変数です。現在の関数呼び出しの期間を超えて存在するはずのものにポインターを格納しても機能しません。

上記が問題の完全なリストであると言っているわけではないことに注意してください。

pthread_mutex_tタイプを a の typedef にしてstruct mutexList*、 の値newMutex(のアドレスではない)newMutexを配置できます。ユーザーの変数には、リンクされたリストにある構造へのポインターが含まれます。*mutexmutexstruct mutexList**pthread_mutex_t

ユーザーが呼び出しpthread_mutex_destroy()を怠り、pthread_mutex_t変数をスコープから外した場合、struct mutexList割り当てられた要素は決して解放されませんが、それはユーザー エラーであり、実際には何もできません。

ミューテックスの初期化に関する限り、まだ考えなければならない別の大きな問題があります - 静的初期化です。ユーザーは次のようなことを行うことができます。

// the following is at file scope, so it has static duration
pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;

この場合、ユーザーは呼び出す必要はありませんpthread_mutex_init()。実際、呼び出すとエラーになります。ライブラリは、最初の使用時にこれらの静的に初期化されたミューテックスに必要な適切な動的初期化 (または同等のもの) を検出して実行する必要があります。そして、スレッドセーフな方法でそれを行う必要があります-最初の使用は任意のスレッドで許可されるだけでなく、これらの静的ミューテックスの主な使用例の 1 つは、すぐにミューテックスで競合を許可することです (たとえば、他の静的データのより複雑な初期化を、たまたまそれに到達した最初のスレッドによって実行します)。

pthread_mutex_t要約すると、プライベートミューテックスデータ構造のコンテナを保持し、ユーザーの変数をコンテナ内の適切な項目へのポインター (またはその他の間接参照) にするという一般的なアプローチは問題ないと思います。ただし、特に関数がスレッドセーフであることを確認するなど、考慮して設計する必要がある複雑な詳細がたくさんあります。

この例に存在する種類の問題は、これまでの設計が十分に検討されていなかったことを示しています。それは大丈夫かもしれません - おそらくあなたはそれを始めたばかりです。これらのことを行うために必要な細部への注意を過小評価しないでください.

于 2012-04-18T09:21:30.830 に答える
0

ユーザーはミューテックスを auto 変数として自由に宣言することも、たとえば から割り当てられたメモリへのポインターとして宣言することもできるためmalloc(3)、ミューテックス構造をグローバル リンク リストに格納することには懐疑的です。ガベージにつながります。(確かに、ユーザーはミューテックスを破棄することになっていますが、私はそれをあまり信頼したくありません。)

pthread_mutex_init(3posix)マンページの次のコードを検討してください。

static pthread_mutex_t foo_mutex;

void foo_init()
{
    pthread_mutex_init(&foo_mutex, NULL);
}

このコードでは -allocated を使用していますが、static-allocatedfoo_mutexにすることもできautoます。新しいものを作成mutexElementし、ポインターを介して代入しようとすると*mutex、この場合、コードは機能しません...

そうは言っても、あなたが探しているものは非常に簡単だと思います:

int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *attr) {
    m->base_address = m;
    /* ... your other work ... */
}
于 2012-04-18T02:53:59.170 に答える