简体   繁体   English

线程和具有相关性的嵌套for循环(C中的pthreads)

[英]Threads and a nested for loop with dependencies (pthreads in C)

Im trying to learn how to program using threads in C by using the pthreads library. 我试图学习如何使用pthreads库在C语言中使用线程进行编程。 In my thread function I have a nested for loop: 在我的线程函数中,我有一个嵌套的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;
}

The calculation in the inner for-loop depends on the result of the previous t-step of the outer for loop, so the threads have to wait for the other threads to finish the current t-step, before continuing. 内部for循环中的计算取决于外部for循环的先前t步的结果,因此线程必须等待其他线程完成当前t步,然后才能继续。 Is there a way to wait for all the threads to finish each t-step before continuing the next t-step? 有没有一种方法可以等待所有线程完成每个t步骤再继续下一个t步骤? I tried to use pthread_join() but that doesn't seem the work within the thread_func() . 我尝试使用pthread_join()但似乎在thread_func()中没有工作。 Can someone point me in the right direction? 有人可以指出我正确的方向吗? Or am I trying something which isn't possible? 还是我正在尝试一些不可能的事情?

EDIT: i and t are local variables in thread_func() ..forgot to mention that.. 编辑:i和t是thread_func()中的局部变量。 thread_func()这一点。

EDIT2: Maybe my explanation is not very clear... Im creating some threads in main() (not shown in the code) and each thread calls thread_func() . EDIT2:也许我的解释不是很清楚...我在main()创建了一些线程main()代码中未显示),每个线程都调用thread_func() I've divided the inner for-loop among the threads. 我在线程之间划分了内部for循环。 But before going to the next t-step in the outer for loop, I should be sure that all threads have finished the current t-step, because the result of the next t-step depends on the result of the current t-step. 但是在进入外部for循环中的下一个t步之前,我应该确保所有线程都已经完成了当前的t步,因为下一个t步的结果取决于当前t步的结果。 How can I do that? 我怎样才能做到这一点? Hope that makes more sense now.. 希望现在更有意义。

You seem to be somewhat confused about how threads work in general. 您似乎对线程通常的工作方式有些困惑。

In reality, thread_func() will not be shared among the different threads you create. 实际上, thread_func()不会在您创建的不同线程之间共享。 Each thread has its own context; 每个线程都有自己的上下文。 even if all of them are executing thread_func() , none of them messes with the computations of the other as far as everything is local. 即使它们全部都在执行thread_func() ,但只要它们都是thread_func() ,它们都不会与另一个的计算混乱。

The only case in which you have to worry about concurrent accesses is with shared data (global variables, for example). 您唯一需要担心并发访问的情况是共享数据(例如,全局变量)。 In this case, you generally use mutexes or semaphores. 在这种情况下,通常使用互斥或​​信号量。 Read about pthread_mutex_t and sem_t 了解有关pthread_mutex_tsem_t

UPDATE: Since you don't specify what exactly is t and i , I assumed they were local variables. 更新:由于您没有指定确切的ti ,所以我假设它们是局部变量。 If they are global, you have to use mutexes to sync access to these variables. 如果它们是全局变量,则必须使用互斥锁来同步对这些变量的访问。 Keep in mind that calling a global variable meaningless names like t or i is generally bad practice. 请记住,调用无意义的全局变量(如ti )通常是不好的做法。

UPDATE2: With your edits, I now understand what you really want. UPDATE2:通过您的编辑,我现在了解您真正想要的是什么。 The only solution I can think of at the moment is that you need to have a global variable that will serve as t for every thread. 目前我能想到的唯一解决方案是,您需要具有一个全局变量,该变量将用作每个线程的t Let's call it step . 我们称它为step step is global because every thread can read it and know what is the current iteration. step是全局的,因为每个线程都可以读取它并知道当前的迭代是什么。 However, to coordinate concurrent access to this variable, we will need a mutex, as I mentioned earlier. 但是,如前所述,为了协调对该变量的并发访问,我们将需要一个互斥体。

The basic layout goes like this: A thread stores the last iteration that was executed inside its context. 基本布局如下:线程存储在其上下文中执行的最后一次迭代。 It is repeatedly testing step to see if it was updated by another thread. 它正在反复测试step以查看它是否已被另一个线程更新。 When that happens, it begins execution of the for loop (the one with i = start; ... . After executing the loop, the thread must test if it was the last one for this iteration; if it was, it must increment the global value for step (note that when this happens, any threads that were stuck waiting for new values for step will move forward). 发生这种情况时,它将开始执行for循环( i = start; ...那个)。执行循环后,线程必须测试它是否是该迭代的最后一个;如果是,则必须递增step全局值(请注意,发生这种情况时,所有等待step新值而阻塞的线程将继续前进)。

Testing if we're the last thread implies that you somehow know the number of threads you created. 测试我们是否是最后一个线程意味着您以某种方式知道您创建的线程数。 You can pass this as a parameter, or define it as a constant. 您可以将此作为参数传递,或将其定义为常量。 I will assume it is defined as THREADS_NO . 我将假定它被定义为THREADS_NO

As a consequence, we will also need a global counter and mutex to know how many threads have ended current iteration 因此,我们还需要一个全局计数器和互斥量来知道有多少线程结束了当前迭代

Thus, your file would look something like: 因此,您的文件将类似于:

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

You have to initialize both mutexes before creating any thread, possibly in main() , with: 您必须在创建任何线程之前main()可能在main()初始化两个互斥锁:

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

And when you get the job done, don't forget to destroy them: 当您完成工作时,不要忘记销毁它们:

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

Note that you should test the return value of the functions that initialize, lock, and destroy mutexes, since an error can occur. 请注意,您应该测试初始化​​,锁定和销毁互斥锁​​的函数的返回值,因为可能会发生错误。

Finally, consider if this is what you really want: maybe you need to redesign your program or algorithm. 最后,考虑一下这是否是您真正想要的:也许您需要重新设计程序或算法。 This approach is not very efficient, because threads will waste CPU cycles to repeatedly test for new values for step (this is called busy waiting). 这种方法不是很有效,因为线程将浪费CPU周期来重复测试step新值(这称为繁忙等待)。 Pretty much like "Are we there yet? Are we there yet? Are we there yet?"... not very clever. 几乎就像“我们到那儿了吗?我们到那儿吗?我们到那儿吗?”……不是很聪明。

NOTE: I couldn't test this code. 注意:我无法测试此代码。 The code you posted makes it a little harder to know what you're trying to achieve, so I'm not sure this will work entirely for you. 您发布的代码使您很难知道要实现的目标,因此,我不确定这是否完全适合您。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM