使用pthread进行线程处理

时间:2010-11-04 05:54:09

标签: c++

假设我有一个包含5个线程的数组:

//main thread
pthread_t t[5];
pthread_mutex_t mutex[5];
queue<int> q[5];

for(int i = 0; i < 5; i++){
pthread_create(&pthread_t[i], NULL, worker, NULL);
}

for(int i = 0; i < 5; i++){
   pthread_mutex_lock(&mutex[i]);
      queue[i].push_back(i);
   pthread_mutex_unlock(&mutex[i]);
}

void* worker(void* arg){

    pthread_mutex_lock(&mutex[?]);      

}

我对此处的mutex_lock感到困惑。我的问题是:

  1. 我怎么能让工人知道要锁定哪个互斥锁?
  2. 当我通过互斥锁[i]访问互斥锁时,我是否需要另一个锁,因为子线程也可能正在访问互斥锁数组?
  3. 感谢。

5 个答案:

答案 0 :(得分:1)

pthread_create的最后一个参数在被调用时被移交给线程,所以你只需要将一个值传递给特定的线程。

由于您需要特定的互斥锁和特定的队列,因此最好直接传递i的值。

for(int i = 0; i < 5; i++){
    pthread_create(&pthread_t[i], NULL, worker, (void*)i);
}

void *worker (void *pvI) {
    int idx = (int)pvI;  // Check for cast problems.
    // Use mutex[idx] and q[idx].
}

但是,如果你想这样做,我会选择一个队列和互斥。

这是因为将某些东西放在队列上的行为几乎肯定会比处理队列中的项目快得多(否则你根本不会需要线程)。

如果你有多个队列,主线程必须弄清楚哪些是未充分利用的线程,以便它可以选择最佳队列。如果您有一个队列和一个互斥锁来保护它,那么线程将自我组织以提高效率。那些做长任务的线程不会尝试从队列中获取内容。做空工作的人会早点回来。


我应该提一下,互斥量本身并不是这个生产者/消费者模型的好解决方案。你不能让线程锁定互斥锁然后无限期地等待队列,因为这会阻止主线程将任何东西放在队列上。

这意味着您的工作线程将不断轮询寻找工作的队列。

如果使用互斥量结合条件变量,它将更有效率。这是因为当工作可用时主线程发出信号而不是经常抓取互斥锁,检查工作,然后释放互斥锁。

基本大纲将是主线程:

initialise
while not finished:
    await work
    lock mutex
    put work on queue
    signal condvar
    unlock mutex
terminate

,对于工作线程:

initialise
while not finished:
    lock mutex
    while queue is empty:
        wait on condvar
    get work from queue
    unlock mutex
    do work
terminate

答案 1 :(得分:1)

您需要清楚哪些线程正在共享哪些队列。您编写的代码表明每个工作线程都在特定队列上工作,但主线程(产生工作线程)会将新值推回到这些队列上。如果这就是你想要的,那么你所做的基本上是正确的,并且你可以让工作线程知道它们要锁定/解锁的互斥锁的数组索引,方法是将它转换为void *并将其作为参数传递给pthread_create,它将作为void *传递给worker函数。在互斥锁阵列周围不需要任何额外的锁定层 - 独立访问特定元素是完全安全的,但如果说它是在运行时调整大小的向量,那么您将需要额外的锁定级别。

答案 2 :(得分:1)

将互斥锁与创建新结构的队列相关联;

typedef struct {

  pthread_mutex_t mutex;
  queue<int> q;

} safe_queue;

safe_queue queue_pool [5];


void* worker(safe_queue){
 pthread_mutex_lock(&safe_queue.mutex);      
}

答案 3 :(得分:0)

不要将NULL指针作为arg传递给线程。而是使用指向对象的指针来定义线程必须执行的操作。

答案 4 :(得分:0)

  

我怎样才能让工人知道锁定哪个互斥锁?

将数字作为最后一个参数传递给pthread_create()

for(int i = 0; i < 5; i++)
{
    pthread_create(&pthread_t[i], NULL, worker, reinterpret_cast<void*>(i));
}

然后你可以得到这样的值:

void* worker(void* arg)
{
    int index = reinterpret_cast<int>(arg);
    pthread_mutex_lock(&mutex[index]);      
}
  

当我通过互斥锁[i]访问互斥锁时,我是否需要另一个锁,因为子线程也可能正在访问互斥锁数组?

没有。因为变量mutex本身永远不会被修改。数组的每个成员都通过pthread_mutext_X()方法以原子方式运行。

稍微好一点的设计是:

//main thread
struct ThreadData
{
    pthread_mutex_t mutex;
    queue<int>      queue;
};
pthread_t   t[5];
ThreadData  d[5];

for(int i = 0; i < 5; i++)
{
    pthread_create(&t[i], NULL, worker, &d[i]); // Pass a pointer to ThreadData
}


void* worker(void* arg)
{
    // Retrieve the ThreadData object.
    ThreadData  d = reinterpret_cast<ThreadData*>(arg);

    pthread_mutex_lock(&(d.mutex));
    <STUFF>      
}