【问题标题】:Order of threads executing in a multiple-thread program多线程程序中执行的线程顺序
【发布时间】:2018-07-19 05:04:42
【问题描述】:

我对线程编码非常陌生,所以我正在做一个我在网上找到的练习,它要求这样的东西:

编写一个程序 hellomany.c,它将创建在命令行中指定的 N 个线程,每个线程都打印出一个 hello 消息和它自己的线程 ID。要查看线程的执行是如何交错的,请让主线程每创建 4 或 5 个线程就休眠 1 秒。您的代码输出应类似于:

   I am thread 1. Created new thread (4) in iteration 0...
   Hello from thread 4 - I was created in iteration 0
   I am thread 1. Created new thread (6) in iteration 1...
   I am thread 1. Created new thread (7) in iteration 2...
   I am thread 1. Created new thread (8) in iteration 3...
   I am thread 1. Created new thread (9) in iteration 4...
   I am thread 1. Created new thread (10) in iteration 5...
   Hello from thread 6 - I was created in iteration 1
   Hello from thread 7 - I was created in iteration 2
   Hello from thread 8 - I was created in iteration 3
   Hello from thread 9 - I was created in iteration 4
   Hello from thread 10 - I was created in iteration 5
   I am thread 1. Created new thread (11) in iteration 6...
   I am thread 1. Created new thread (12) in iteration 7...
   Hello from thread 11 - I was created in iteration 6
   Hello from thread 12 - I was created in iteration 7

我编写的代码是这样的:

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

void* PrintHello(int iteration)
{
    printf("Hello from thread %u - I was created in iteration %d \n", 
    pthread_self(), iteration);
    pthread_exit(NULL);                 
}

int main(void)
{
    int        rc;                
    pthread_t  thread_id;             
    int        tidMain;
    int        n, i;

    tidMain = pthread_self();

    printf("How many threads are there to be created?\n");
    scanf("%d", &n);

    for(i = 1; i <= n; i++) {

        pthread_t thread_id;
        rc = pthread_create(&thread_id, NULL, PrintHello, i);
        printf("I am thread %u. Created new thread (%u) in iteration %d\n", 
        tidMain, thread_id, i);
        if(rc)                             
        {
            printf("\n ERROR: return code from pthread_create is %d \n", rc);
            exit(1);
        }
        if((i % 5) == 0) {
            sleep(1);
        }

    }

    pthread_exit(NULL);
}

该程序确实打印了我想要的内容,甚至会休眠并“破坏”每 5 个线程创建的创建;仍然,我不知道为什么,但是当每个创建的线程在我想要的 5-thread-printing-streak 中执行(在主线程通知它们已创建之后)时,首先“问候”的线程是最后创建的线程。我从控制台得到的,即当我要求它创建 8 个线程时,是这样的:

I am thread 3075630848. Created new thread (3075627840) in iteration 1
I am thread 3075630848. Created new thread (3067235136) in iteration 2
I am thread 3075630848. Created new thread (3058842432) in iteration 3
I am thread 3075630848. Created new thread (3050449728) in iteration 4
I am thread 3075630848. Created new thread (3042057024) in iteration 5
Hello from thread 3042057024 - I was created in iteration 5 
Hello from thread 3050449728 - I was created in iteration 4 
Hello from thread 3058842432 - I was created in iteration 3 
Hello from thread 3067235136 - I was created in iteration 2 
Hello from thread 3075627840 - I was created in iteration 1 
I am thread 3075630848. Created new thread (3032480576) in iteration 6
I am thread 3075630848. Created new thread (3024087872) in iteration 7
I am thread 3075630848. Created new thread (3015695168) in iteration 8
Hello from thread 3015695168 - I was created in iteration 8 
Hello from thread 3024087872 - I was created in iteration 7 
Hello from thread 3032480576 - I was created in iteration 6

据我了解,它首先执行的是最后创建的线程。为什么会这样?我可以让它先执行第一个创建的吗?

顺便说一句:我在 Ubuntu 上运行

【问题讨论】:

标签: c multithreading pthreads


【解决方案1】:

这是关于并发编程的重点。您永远不能对线程执行的顺序做出任何假设。例如,我得到以下输出:

I am thread 639280960. Created new thread (630781696) in iteration 1
Hello from thread 630781696 - I was created in iteration 1
I am thread 639280960. Created new thread (622388992) in iteration 2
Hello from thread 622388992 - I was created in iteration 2
I am thread 639280960. Created new thread (613996288) in iteration 3
Hello from thread 613996288 - I was created in iteration 3
I am thread 639280960. Created new thread (536868608) in iteration 4
Hello from thread 536868608 - I was created in iteration 4
I am thread 639280960. Created new thread (526280448) in iteration 5
Hello from thread 526280448 - I was created in iteration 5
I am thread 639280960. Created new thread (517887744) in iteration 6
I am thread 639280960. Created new thread (509495040) in iteration 7
Hello from thread 509495040 - I was created in iteration 7
I am thread 639280960. Created new thread (501102336) in iteration 8
Hello from thread 501102336 - I was created in iteration 8
Hello from thread 517887744 - I was created in iteration 6

如果我再次运行它,我可能会得到不同的输出。自己试试吧!

Wikipedia Article about Concurrent computing 表示:

并发系统中任务执行的确切时间 依赖于调度,并且任务不需要总是被执行 同时。例如,给定两个任务,T1 和 T2:

  • T1 可以在 T2 之前执行和完成,反之亦然(串行和顺序)

  • T1 和 T2 可以交替执行(串行和并发)

  • T1 和 T2 可以在同一时刻同时执行(并行和并发)

我建议你阅读一些关于并发和并行性的基本文章或文献。

【讨论】:

  • 我明白了!谢谢,我知道它们是不确定的,但执行顺序大多像堆栈让我有点奇怪。猜猜这是随机性的问题
【解决方案2】:

这是一个并发程序。如果您多次运行程序,即使在同一主机中,顺序也可能不同。

顺便说一句,也许你最好在编码之前先看看pthread API。

对于pthread_create()

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

第三个参数是void *(*start_routine)(void *)而不是void *(start_routine)(int),第四个参数是void *而不是int

【讨论】:

    【解决方案3】:

    线程执行的顺序未确定。如果您需要特定的顺序,则必须使用锁、互斥锁和条件来按您的要求对其执行进行排序。

    您看到的顺序是由您的硬件和内核引起的,有时是由随机性引起的。我假设您有一个单核 CPU,否则输出将毫无意义。当您创建一个线程时,您的内核只是安排线程稍后运行并继续执行主线程。因此,您会收到所有 5 个线程创建的消息。只有当主线程休眠时,内核才会切换到准备运行的下一个线程。它似乎以 FILO 的方式执行此操作(先进后出)。这恰好是您的硬件版本中的内核发生的事情。随时可能改变。

    另一方面,pOwl 似乎有多个核心。因此,当主线程创建线程时,其他核心已经执行它们。或者他只是有一个不同的内核。

    【讨论】:

    • 我确实有一个四核 CPU。但是,idk,也许是因为我在 LUbuntu VM 上运行?
    最近更新 更多