1

メインスレッドが接続を取得してスレッドに渡し、スレッドがそれを処理するスレッドプールを使用してWebサーバーをプログラムしようとしています。

各スレッドの構造体と、それらを保持するためのworkQueueがあります

struct worker {
    pthread_t* thread;
    struct queue* workerQueue;
    char* busy;
    int connfd;
    int id;
};

struct queue {
    int start;
    int end;
    int size;
    struct worker* workers;
};

メインスレッドはキューとスレッドを設定し、接続をループします

  struct queue* workerQueue;
            workerQueue = (struct queue*) constructQueue(10);
            int j;
            int* testParam;
            //create workers and put in queue
            for(j=0;j<5;j++)
            {
                struct worker* w = &(workerQueue->workers[j]);
                w = (struct worker*)constructWorker(processConnection,testParam, workerQueue,j);
                queueAdd(workerQueue,w);
            }
connection = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
        puts("got connection\n");


         w =(struct worker*) queueRemove(workerQueue);
        //w->connfd = connection;
        w->busy = "BUSY";
        printf("Worker %d has accepted a connection and is %s\n",w->id,w->busy);

これらの2つの関数を使用します。

   struct queue* constructQueue(int numThreads)
    {
        struct queue* q = (struct queue *)malloc(sizeof(struct queue));
        q->start = 0;
        q->end = 0;
        q->workers = (struct worker* )malloc(sizeof(struct worker)*numThreads);
        q->size = numThreads;
        return q;
    }

struct worker* constructWorker(void* (*function)(void*),void* param, struct queue* wq, int i)
{
    struct worker* w = (struct worker*)malloc(sizeof(struct worker));
    w->workerQueue = wq;
    char * busy = (char*)malloc(10);
    w->busy= "IDLE";
    w->connfd = 0;
    w->id = i;
    pthread_t t;
    w->thread = &t; 
    pthread_create(w->thread,NULL,function,w);
    return w;
}

...そしてスレッドが使用する機能は

void* processConnection(void* serverThread)
{
        //cast serverthread
        struct worker* w;
        char* b;
        int threadID;
        w = (struct worker*)serverThread;
        b = w->busy;
        threadID = w->id;


        while (1)
        {
            char c[10];
            printf("\nbusy: %s, thread: %d\n",b,threadID);
            gets(c)

;

私がしたいのは、ビジーをIDLEに設定して、ワーカーを作成し、ビジーウェイトを開始することです。次に、メインループで、接続が受け入れられてワーカーに割り当てられ、ワーカーのビジー値がBUSYに設定されます。次に、processConnectionsで、スレッドがビジーの場合、実際に処理する必要があります。問題は、キューに値ではなくポインターが含まれているにもかかわらず、メインスレッドのワーカーを更新しても、processConnectionのワーカーの値に影響を与えていないように見えることです。ビジーをビジーに設定してメインループに出力させることはできますが、ビジーの値はprocessConnectionでは常にIDLEです。何か案は?

4

3 に答える 3

1

スレッド間に同期ポイントがないため、他のスレッドに更新された値が表示されていない可能性があります。コンパイラの最適化とキャッシュの(不)一貫性が、これが発生する2つの理由です。同じ戦略を維持するには、メモリバリアが必要です。gccを使用している場合、最も簡単な方法は__sync_synchronize()、共有データを読み取る前と、共有データを書き込んだ後に配置することです。

あなたが修正する必要があるもう一つのことはあなたがするときです

pthread_t t;
w->thread = &t;

のメモリはt、その関数が戻った後に再利用される可能性があります。ローカル変数のアドレスを取得して、関数の存続期間を超える方法で格納することはできません。適切な方法は、フィールドを入れて、pthread_tフィールドstruct workerのアドレスを次のアドレスに渡すことpthread_createです。

pthread_create(&w->thread, ...);
于 2013-02-26T04:46:29.723 に答える
1

の定義をbusyto に変更してみてください

volatile char * busy;

これにより、コードがその変数に明示的にアクセスしていなくても、コードの実行中にこの変数の値が変更される可能性があることがコンパイラに通知されます。

ただし、他にも多くの問題があります。例えば、

char * busy = (char*)malloc(10);
w->busy= "IDLE";

によって割り当てられたメモリがリークしますmalloc。状態を追跡するために文字列を使用しようとしないでください。enum {IDLE, BUSY}代わりに を定義し、その型の変数であると定義しbusyます。

于 2013-02-26T05:33:19.290 に答える
0

2つのミューテックスをワーカーに1つ、キューに1つ追加することをお勧めします

   struct worker {
      pthread_t* thread;
      struct queue* workerQueue;
      mutex_t QueueMutex;
      char* busy;
      int connfd;
      int id;
      };`

   struct queue {
       int start;
       int end;
       int size;
       mutex_t workermutex;
       struct worker* workers;
   };

コードは次のように機能するはずです

新しいソケットを作成するときは、workermutexをロックしてから、接続を割り当てます

ワーカースレッドは毎回QueueMutexをロックし、処理のためにキューからデータを追加/削除します。

于 2013-02-26T20:21:56.573 に答える