线程和带有依赖项的嵌套for循环(C中的pthreads)

时间:2013-11-08 16:19:48

标签: c multithreading loops pthreads nested

我试图学习如何使用pthreads库在C中使用线程进行编程。在我的线程函数中,我有一个嵌套的for循环:

void* thread_func(void* a) {
    int i, t;
    struct type *b = (struct type*)a;
    int start = b->start;
    int stop = b->stop;
    for(t = 0; t < 1000; t++) {

        for(i = start; i < stop; i++) {
        /* This inner loop is evenly divided among the threads.*/
        /***** Calculation*****/
        }
    }
    return NULL;
}

内部for循环中的计算取决于外部for循环的前一个t步骤的结果,因此在继续之前,线程必须等待其他线程完成当前的t步骤。有没有办法在继续下一个t步骤之前等待所有线程完成每个t步骤?我尝试使用pthread_join(),但这似乎不是thread_func()中的工作。有人能指出我正确的方向吗?或者我在尝试一些不可能的事情?

编辑:我和t是thread_func()中的局部变量..忘记提及..

EDIT2:也许我的解释不是很清楚......我在main()中创建了一些线程(未在代码中显示),每个线程都调用thread_func()。我在线程中划分了内部for循环。但是在进入外部for循环的下一个t步之前,我应该确保所有线程都已完成当前的t步,因为下一个t步的结果取决于当前t步的结果。我怎样才能做到这一点?希望现在更有意义..

1 个答案:

答案 0 :(得分:1)

您似乎对线程的工作方式感到有些困惑。

实际上,thread_func()不会在您创建的不同主题之间共享。每个线程都有自己的上下文;即使所有这些都在执行thread_func(),只要一切都是本地的,它们都不会混淆另一方的计算。

您必须担心并发访问的唯一情况是共享数据(例如全局变量)。在这种情况下,您通常使用互斥锁或信号量。阅读pthread_mutex_tsem_t

更新:由于您未指定ti到底是什么,我认为它们是局部变量。如果它们是全局的,则必须使用互斥锁来同步对这些变量的访问。请记住,调用全局变量无意义的名称(如ti)通常是不好的做法。

UPDATE2:通过编辑,我现在明白了你真正想要的。我现在能想到的唯一解决方案是你需要有一个全局变量,它将作为每个线程的t。我们称之为stepstep是全局的,因为每个线程都可以读取它并知道当前迭代是什么。但是,为了协调对此变量的并发访问,我们需要一个互斥锁,如前所述。

基本布局如下:一个线程存储在其上下文中执行的最后一次迭代。它反复测试step以查看它是否被另一个线程更新。当发生这种情况时,它开始执行for循环(具有i = start; ...的循环。执行循环后,线程必须测试它是否是此迭代的最后一个循环;如果是,则必须增加step的全局值(请注意,当发生这种情况时,任何等待step的新值的线程都将向前移动。

测试我们是否是最后一个线程意味着您以某种方式知道您创建的线程数。您可以将其作为参数传递,或将其定义为常量。我将假设它被定义为THREADS_NO

因此,我们还需要一个全局计数器和互斥锁来知道有多少线程结束当前迭代

因此,您的文件看起来像:

pthread_mutex_t step_mutex;
pthread_mutex_t counter_mutex;

int step;
int counter;

void* thread_func(void* a) {
    int t, i, curr_t;
    struct type *b = (struct type*)a;
    int start = b->start;
    int stop = b->stop;
    t = -1;
    curr_t = 0;
    while (1) {
        while (curr_t == t) {
            /* Wait for the next step */
            pthread_mutex_lock(&step_mutex);
            curr_t = step;
            pthread_mutex_unlock(&step_mutex);      
        }
        /* New value for t arrived */
        t = curr_t;
        if (t >= 1000) {
            break;
        }
        for (i = start; i < stop; i++) {
            /***** Calculation*****/
        }
        pthread_mutex_lock(&counter_mutex);
        if (++counter == THREADS_NO) {
            counter = 0;
            pthread_mutex_lock(&step_mutex);
            step++;
            pthread_mutex_unlock(&step_mutex);
        }
        pthread_mutex_unlock(&counter_mutex);
    }   
    return NULL;
}

您必须在创建任何线程之前初始化两个互斥锁,可能在main()中,使用:

pthread_mutex_init(&step_mutex, NULL);
pthread_mutex_init(&counter_mutex, NULL);

当你完成工作时,不要忘记销毁它们:

pthread_mutex_destroy(&step_mutex);
pthread_mutex_destroy(&counter_mutex);

请注意,您应该测试初始化​​,锁定和销毁互斥锁​​的函数的返回值,因为可能会发生错误。

最后,请考虑这是否是您真正想要的:也许您需要重新设计您的程序或算法。这种方法效率不高,因为线程会浪费CPU周期来重复测试step的新值(这称为忙等待)。非常像“我们还在吗?我们还在吗?我们还在吗?”......不是很聪明。

注意:我无法测试此代码。您发布的代码让您更难以了解您要实现的目标,因此我不确定这是否会完全适合您。