【问题标题】:Can't share variables between pthreads, values are different不能在 pthread 之间共享变量,值不同
【发布时间】:2013-02-11 10:22:41
【问题描述】:

我正在尝试使用线程池对 Web 服务器进行编程,主线程在其中获取连接,将其传递给线程,然后线程对其进行处理。

每个线程都有一个结构体,还有一个工作队列来保存它们

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

使用这两个函数..

   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)

;

我希望发生的事情是:创建工人,忙设置为空闲,并开始忙等待。然后在主循环中,一个连接被接受并分配给一个worker,worker的busy值被设置为BUSY。然后在 processConnections 中,如果一个线程很忙,它应该实际处理它。问题是,虽然我的队列包含指针而不是值,但是当我在主线程中更新工作人员时,它似乎不会影响 processConnection 中工作人员的值。我可以将busy设置为BUSY并让它在主循环中打印出来,但是busy的值在processConnection中总是IDLE。有什么想法吗?

【问题讨论】:

  • 如果同时访问一个变量,访问它应该使用互斥锁序列化。对于pthreads,这可以使用pthread_mutex_t 类型的变量来完成。请阅读man pthread_mutex_init

标签: c multithreading struct pthreads


【解决方案1】:

我建议添加 2 个互斥锁,一个在工作线程,一个在队列

   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并从队列中添加/删除数据进行处理。

【讨论】:

    【解决方案2】:

    尝试将busy 的定义更改为

    volatile char * busy;
    

    这告诉编译器这个变量的值可以在代码运行时改变,即使代码没有显式访问那个变量。

    但是,您还有许多其他问题。例如,

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

    将泄漏由malloc 分配的内存。 不要尝试使用字符串来跟踪状态。改为定义 enum {IDLE, BUSY} 并将 busy 定义为该类型的变量。

    【讨论】:

    • 没什么 :( 不过还是谢谢。我知道内存泄漏,但它次要于让该死的东西工作......
    • volatile 并不意味着用于序列化对在不同线程之间同时使用的变量的访问。为此使用互斥锁。
    • 不仅泄漏,而且 malloc 不做任何事情。 busy 和 w->busy 是两个完全不同的位置,即使它们是,“IDLE”也是分配给的静态字符串。根本没有写入 malloc 的存储。
    【解决方案3】:

    您可能没有在另一个线程中看到更新的值,因为线程之间没有同步点。编译器优化和缓存(内)一致性是发生这种情况的两个原因。要保持相同的策略,您需要一个内存屏障。如果你使用 gcc,最简单的方法是在读取共享数据之前和写入共享数据之后放置__sync_synchronize()

    您需要解决的另一件事是何时进行

    pthread_t t;
    w->thread = &t;
    

    t 的内存可能会在该函数返回后被重用。您不能获取局部变量的地址并将其存储在超出函数生命周期的方式中。正确的做法是在struct worker 中有一个pthread_t 字段并将该字段的地址传递给pthread_create

    pthread_create(&w->thread, ...);
    

    【讨论】:

    • 修复了 pthread 创建问题,干杯。不幸的是 syncchronise() 什么也没做。我也尝试加入一些互斥锁,但它们似乎只是造成了死锁
    猜你喜欢
    • 2016-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-20
    • 1970-01-01
    • 1970-01-01
    • 2019-01-30
    相关资源
    最近更新 更多