【问题标题】:More effective concurrent solution更有效的并发解决方案
【发布时间】:2012-10-20 05:11:45
【问题描述】:

我现在正在上一门关于并发的课程,我已经完成了我的第一个(非常简单的)项目,现在我想让它变得有用。

在我的代码中,我正在通过一个数组对第二个数组的每个值进行二进制搜索。对于第二个数组中的每个值,我正在生成一个线程。结果证明这比顺序解决方案要慢,所以我的想法是,我会生成少量线程,并在每次完成执行时向它们传递一个新键。

我有几个问题。首先是,当没有更多的键时如何让线程退出?

如何传递新密钥?

如何让线程在等待新键时不使用旧键执行(我一直在阅读有关条件等待的内容,并认为这就是我需要的)。

这是我目前(无效)的解决方案。

#define ARRAYSIZE 50000
#define KEY_NOT_FOUND -1
#define KEY_FOUND 0

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h> 

int binary_search(int *array, int key, int min, int max); 
void *worker(void *arg);

int count = 0;
pthread_mutex_t L;
int l_array[ARRAYSIZE * 2];

int main(void)
{
    int r_array[ARRAYSIZE]; 
    int *p;
    pthread_t *threads;
    int ix = 0;
    int jx = 0;

    struct timeval start, stop;
    double elapsed;

    for(ix = 0; ix < ARRAYSIZE; ix++)
    {
        r_array[ix] = ix;
    }
    for(ix = 0; ix < ARRAYSIZE * 2; ix++)
    {
        l_array[ix] = ix + 2;
    }

    gettimeofday(&start, NULL);

    threads = (pthread_t *) malloc(ARRAYSIZE * sizeof(pthread_t));

    for (jx = 0; jx < ARRAYSIZE; jx++) {
         p = (int *) malloc(sizeof(int));  
        *p = r_array[jx];
        pthread_create(&threads[jx], NULL, worker, (void *)(p));
    }

    for (jx = 0; jx < ARRAYSIZE; jx++) {
        pthread_join(threads[jx], NULL);
    }

    fprintf(stderr, "%d\n", count);

    gettimeofday(&stop, NULL);
    elapsed = ((stop.tv_sec - start.tv_sec) * 1000000+(stop.tv_usec-start.tv_usec))/1000000.0;
    printf("time taken is %f seconds\n", elapsed);
    return 0;
}

void* worker(void *arg)
{
    int boolean = 0;
    int key = *((int *) arg);
    boolean = binary_search(l_array, key, 0, ARRAYSIZE * 2);
    if(boolean == 1)
    {
        pthread_mutex_lock(&L);
        count++;
        pthread_mutex_unlock(&L);
    } 
}

int binary_search(int *array, int key, int min, int max)
{
   int mid = 0;
    if (max < min) return 0;
    else
    {
      mid = (min + max) / 2;
      if (array[mid] > key) return binary_search(array, key, min, mid - 1);
      else if (array[mid] < key) return binary_search(array, key, mid + 1, max);
      else 
        {
        return 1;
        }
    }
}

【问题讨论】:

  • 创建 50000 个线程!大号ARRAYSIZE 50000
  • 好的,线程数多少比较合理?
  • 你可以建立一个线程池,每个核心一个线程,所以今天是 4 或 8 个用于基本桌面
  • 您可以通过对您的程序进行计时来发现这一点。而不是传递单个元素,而是传递r_array 的基地址(就好像它是一个队列一样)。跟踪next_index 的另一个变量。用于修改 next_index 的 pThreadMutEx。
  • 好的,我正在接受您的建议,目前正在修改代码。由于我将拥有多个锁,我现在不得不担心死锁。我知道必须为资源设置优先级,我猜你使用互斥体属性来做到这一点。我还应该避免哪些陷阱?

标签: c concurrency pthreads


【解决方案1】:

注意:以下代码未经测试,但很容易......

  • r_array[]的基地址传递给worker
  • 保持全局next_index
  • 定义另一个pthread_mutex

PS:与线程数一样,从 2 开始,直到您发现吞吐量没有差异为止。你也需要考虑所有的开销。

void worker(void *arg)
{
    int* r_arrPtr = (int*) arg;
    int boolean = 0;
    int key =0;[

    while (1) {
        pthread_mutex_lock(&pNextIndex_MutEx);
        if (next_index < ARRAYSIZE) {
            key = r_arrPtr[next_index];
            next_index ++;
        } else {
            pthread_mutex_unlock(&pNextIndex_MutEx);
            return;
        }
        pthread_mutex_unlock(&pNextIndex_MutEx);

        boolean = binary_search(l_array, key, 0, ARRAYSIZE * 2);
        if (boolean == 1) {
            // ....
        }
    }
}

【讨论】:

  • 检查你传递给binary_search的索引。 max(ARRAYSIZE * 2 -1)
  • 于是我测试了这个方案,发现4个线程导致没有区别。 (有时它更慢,有时它更快)。非常感谢你的帮助。 =D
【解决方案2】:

我建议构建一个线程池,每个内核一个线程,所以今天基本桌面需要 4 或 8 个。

"Divide and conquer" 策略的应用程序pf 中,对于每个线程,您都会为每个线程分配部分搜索。在控制器和工作人员之间存在“生产者/消费者”关系:可以使用阻塞队列。工作人员等待作业,控制器将作业排入队列。

“工作”可能是一个包含所有工作信息的结构。

【讨论】:

    猜你喜欢
    • 2021-05-06
    • 1970-01-01
    • 2015-09-12
    • 1970-01-01
    • 2019-06-30
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    相关资源
    最近更新 更多