【问题标题】:pthread_create does not execute properlypthread_create 未正确执行
【发布时间】:2014-02-19 08:14:20
【问题描述】:

我正在学习多线程程序,并希望下面的 sn-p 代码是打印“foo"”的无限循环,而不是什么都没有发生

期望:

foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo

现实:

好像连线程都没有创建,我做错了什么???我如何创建一个线程来执行分配给它的任何功能

源代码

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

#include <stdio.h>

#include <string.h>
#include <iostream>

void* print(void*);

struct threadInfo
{

    int threadID;
    int threadNo;

};

int main()
{
    pthread_t thread[3];
    bool cont = false;
    int i = 1;
    int max = 3;

    while ( cont == false )
    {
        if ( i <= max )
        {
            threadInfo t_info;
            t_info.threadID = i ;
            t_info.threadNo = i ;
            pthread_create(&thread[i-1],NULL,print,(void*)&t_info);

            i++;
        }
    }   





}

void* print(void* arg)
{
  std::cout << "Foo" ; 
  pthread_exit(NULL);
}

以下代码是在 Ubuntu 命令行上使用以下命令编译的

g++ test.cpp -o test -lpthread

【问题讨论】:

  • 检查phread_create的返回值,不检查是坏习惯
  • 我猜你的线程没有刷新它们的输出......但即便如此,你也只会得到 FooFooFoo,即每个线程一个 Foo

标签: c++ c multithreading debugging posix


【解决方案1】:

线程已创建,但在它们运行之前,主线程退出,您的程序终止(它也是 UB)。你必须等待你的线程:pthread_join

while ( cont == false ) 不需要。

【讨论】:

  • 主线程真的退出了吗?不是无限循环吗?
  • @erenon 它是一个无限循环,我看不到主线程如何在子线程之前退出
【解决方案2】:

没有打印任何内容,因为输出缓冲区没有刷新

print 函数中,例如

std::cout << "Foo" << std::flush;

【讨论】:

  • 为什么我必须刷新输出缓冲区?为什么 foo 的输出在 3 次后停止,应该是无限的吗??
  • @Computernerd 因为它不是自动完成的。如果缓冲区没有被刷新,则实际上什么都不会打印,它只是存储在内存缓冲区中。
  • 在一个正常的程序里,我只能 cout 并自动刷新
  • @Computernerd 当文件对象关闭时,缓冲区会被刷新,就像程序退出时一样。如果您没有退出程序,则不会自动刷新。当然,缓冲区在溢出时会被刷新,但由于缓冲区可能任意大,您无法知道何时会发生这种情况。
【解决方案3】:

天哪……从哪里开始?

Joachim Pileborg 给出了您看不到任何东西的原因:线程创建得很好并完成了它们的工作,但是由于您的主程序永远不会退出并且没有人输出换行符,因此行缓冲输出永远不会刷新。

您的主程序在一个永远不会更改的标志上浪费 CPU 循环。尽管愚蠢的新 C++11 扩展使原子变量成为线程编程的 alpha 和 omega,但尝试将线程与标志同步是非常糟糕的。
您必须使用某种同步来等待线程终止。最常用的机制是pthread_join

将相同的参数实例传递给线程的每个实例会创建一个完美的竞争条件。您无法保证线程会按照您的预期顺序读取参数(即在主循环更改它们以准备下一个线程启动之前)。您应该向每个线程传递其自己的 t_info 私有实例(或在此结构上设置某种同步机制)。

即使解决了所有这些问题,您也应该只期望 3 个“Foo”,因为每个线程在一次打印后退出。

而且由于您没有序列化 cout 访问(即您没有使用某种同步对象(如互斥锁)来保护它们),因此您的各种线程的输出可能会随机混合(即你会看到类似“FoFFooooo”的东西。

【讨论】:

  • 您的 if ( i &lt;= max ) 测试阻止创建超过 3 个线程。
  • 我将 i 设为全局变量并在 print 函数中添加 i-- ,新程序打印 foo 200 次但仍不是无限
  • 这里你又在你的主程序和你的线程之间通过增加/减少一个不受保护的计数器来创建一个竞争条件。您必须了解标志和计数器不是在任务之间共享信息的解决方案,更不用说控制它们的同步了。
  • 如何使用互斥锁控制计数器,保证打印功能无限循环
  • 现在是时候打开一本教科书,看看同步对象的全部内容了。这不是几句话就能解释的简单的事情。它需要理论背景和大量实践才能掌握。
【解决方案4】:

主线程可能在任何其他线程打印出任何内容之前结束(并以此为所有其他线程颤抖)。

要解决此问题,请在结束前在所有其他线程上使主线程加入循环(pthread_join() 用于创建的所有线程 ID),或者使用 pthread_exit() 结束主线程。


同时传递struct threadInfosame 实例的地址(即:(void*)&amp;t_info)很可能不是您想要的。

【讨论】:

    【解决方案5】:

    pthread 没有任何问题。如果要确保输出中的顺序,则需要在打印输出行中加上锁和刷新,以便强制执行,

    1. A thread only finishes once the message has actually been printed out
    2. Threads wait for each other so that no two threads write to the output at the same time
    

    【讨论】: