多线程中的执行流程是怎样的?

What is the flow of execution in Multi-threading?

我遇到了多线程问题。请考虑以下代码:

#include<stdio.h>
#include<pthread.h>

void* functionA(void*);
void* functionB(void*);


int main()
{   
    pthread_t tid[2];
    pthread_attr_t arg;

    for(int i = 0; i<2; ++i)
    {
        pthread_attr_init(&arg);

        if(i == 0)
        {
            int x = 0;  
            pthread_create(&tid[i], &arg, functionA, (void*)&x);
        }

        else if(i == 1)
        {
            int x = 6;  
            pthread_create(&tid[i], &arg, functionB, (void*)&x);
        }
    }

 // wait for both threads to finish execution...    
 pthread_join(tid[0], NULL);
 pthread_join(tid[1], NULL);

 return 0;
 }


//.........................DEFINATIONS........................

void* functionA(void* x)
{
    int Index = *((int*)x);
    printf("First: %d\n",Index);    //..................... LINE M
}


void* functionB(void* x)
{
    int Index = *((int*)x);
    printf("Second: %d\n",Index);   //....................... LINE N
}

现在我相信 functionA 将首先开始执行,因为当然 functionA 的线程将首先在 for 循环中创建,所以根据我的输出应该是:

  First: 0                         (from Line M)
  Second: 6                        (from Line N)

但实际输出是,

  Second: 6
  First: 6

现在看到这个真的很吃惊,不知道怎么回事。不仅 secondFunction 首先开始执行,而且两个函数都显示相同的值,即 6,这对我来说没有意义。谁能解释一下这里发生了什么???? 提前致谢...

您将指向短期局部变量的指针传递给线程,一旦这些作用域退出就会导致未定义的行为。可能两个线程都看到相同的地址 x.

最明显的解决方法是为变量使用更大的范围,并为每个线程创建一个整数数组:

 pthread_t tid[2];
 pthread_attr_t arg;
 int x[2] = { 0, 6 };
 void * (*func[])(void *) = { functionA, functionB };

 for(int i = 0; i < 2; ++i)
 {
     pthread_attr_init(&arg);
     pthread_create(&tid[i], &arg, func[i], &x[i]);
 }

 // wait for both threads to finish execution...    
 pthread_join(tid[0], NULL);
 pthread_join(tid[1], NULL);

这是有效的,因为 x 数组将在调用 pthread_join() 之后继续存在。也不需要转换指针,int * 在 C 中自动转换为 void *

您关于线程启动顺序的假设也是错误的,没有这样的保证。

两件事

1) 这里x变量作用域仅限于if块。所以在你的线程函数中,当你访问该指针时,它的范围已经消失所以你在线程函数中访问非法内存是错误的,它会产生未定义的行为。

回应您的一条评论

所以有什么办法可以直接发送一个常量而不是变量,例如 pthread_create(&tid[i], &arg, functionA, 6) ??

POSIX threads is a C API. C does not provide language facilities like copy constructors and so it is not possible to copy any object by value.

你只需要通过指针传递一些东西。

2) 线程执行的优先级完全 OS 并且取决于计划,您不能假设这些线程的顺序。

你仍然希望线程之间有一些同步,然后使用互斥锁、条件变量等。

无法保证它们的顺序 运行。创建线程时,操作系统的调度程序将注册新线程,并在有时间时 运行 它。基于优先级和系统上的其他 hings 它可能会以任何顺序选择它们,即中断主线程并启动其他线程之一,或者 运行 主线程直到加入然后启动任何其他线程。

您可能正在多核系统上进行测试。那么这些甚至可能 运行 同时并行,但由于某种原因,一个或另一个可能更快(也许来自第二个的数据在缓存中,而第一个必须从内存中获取数据?)

长话短说:没有任何保证。

如果您需要特定的顺序,您可以使用锁(即互斥锁)来强制同步,或者您可以设置优先级(请参阅 setpriority())或强制实时调度(sched_setscheduler()),但是你真的应该了解你的操作系统。

I believe that functionA will start its execution first, because ofcourse thread for functionA will be created first in for loop

这个假设是不正确的,它依赖于由 OS 控制的线程调度。

如果你想看到正确的输出,请在 main() 函数范围内声明两个变量(在 for 循环之前)

int x = 0;  
int y = 6;  

并在

中进行更改
pthread_create(&tid[i], &arg, functionA, (void*)&x);
 pthread_create(&tid[i], &arg, functionB, (void*)&y);

通过这样做,您至少可以获得正确的输出。