C ++线程意外地打印多次相同的行

时间:2015-01-05 14:04:06

标签: c++ linux multithreading g++

我正在编写一个程序,只是为了通过打印每个线程中的内容来查看线程的调度。我得到的是一些意想不到的输出。

虽然我在循环中的每个print语句之后更新了我的变量的值,但是输出显示print语句在更新其值之前多次执行相同的变量值。

为什么会这样?

我期待以下结果,

53674444272163,T35,1
53674444562178,T35,2
53674444563927,T35,3
53674444565225,T35,4

但实际上我得到了以下结果。

53674444272163,T35,1
53674444272163,T35,1
53674444272163,T35,1
53674444272163,T35,1
53674444272163,T35,1
53674444272163,T35,1
53674444272163,T35,1
53674444562178,T35,2
53674444562178,T35,2
53674444562178,T35,2
53674444562178,T35,2
53674444562178,T35,2
53674444562178,T35,2
53674444562178,T35,2
53674444563927,T35,3
53674444563927,T35,3
53674444563927,T35,3
53674444563927,T35,3
53674444563927,T35,3
53674444563927,T35,3
53674444563927,T35,3
53674444565225,T35,4
53674444565225,T35,4
53674444565225,T35,4
53674444565225,T35,4
53674444565225,T35,4
53674444565225,T35,4
53674444565225,T35,4

这是我的计划

#include <pthread.h>
#include <stdio.h>
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <sys/time.h>
#include <time.h>       /* time_t, struct tm, time, localtime */
#include <mutex>          // std::mutex
#include <sstream>
#include <sys/resource.h>
#include <sys/types.h>
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>

#define NTHREADS 100
#define MAX_COUNT 1000

using namespace std;
std::ostringstream out1;
ofstream fp1;

pthread_mutex_t     mutex1 = PTHREAD_MUTEX_INITIALIZER;

unsigned long long int rdtsc_start(void)
{
   unsigned a, d;
   __asm__ volatile("rdtsc" : "=a" (a), "=d" (d));
   return ((unsigned long long)a) | (((unsigned long long)d) << 32);;
}

/* This is our thread function.  It is like main(), but for a thread*/
void *threadA(void *arg)
{ 
    long my_id = (long)arg;
    int check=0;
    volatile long count = 0;
    int j=0;
    while(count++< MAX_COUNT)
    {
        unsigned long long time_x=rdtsc_start();
        pthread_mutex_lock(&mutex1);
        out1<<time_x<<",T"<<my_id<<","<<count<<"\n";
        pthread_mutex_unlock(&mutex1);

        // busy wait  to consume CPU
        volatile long  ii=0;
        while(ii++<50000);
    }
    fp1<<out1.str();
    pthread_exit(NULL);
    return NULL;
}

int main(void)
{
    pid_t pid;
    pid=getpid();

    printf("Thread pid %d\n",pid);

    fp1.open("result_Threaded_Process1.txt"); // in place of parent process 

    pthread_t             threadid[NTHREADS];
    int result;
    //printf("Create %d threads\n", NTHREADS);
    for(long i=0; i<NTHREADS; ++i) 
    {
        result= pthread_create(&threadid[i], NULL, threadA, (void *)i);
        if(result ==-1)
        {
            perror("Thread Creation Error: \n");
            exit(EXIT_FAILURE);
        }    
    }

    //  printf("Wait for threads and cleanup\n");
    for (long i=0; i<NTHREADS; ++i)
    {
        pthread_join(threadid[i], NULL);
    }
    fp1.close(); 
    return 0;
}

我在哪里犯错误? 提前感谢任何线索或提示,以了解输出。

我在Ubuntu 12.04下使用g ++。

编辑

接受的答案:

根据@Jason的评论,当我把

pthread_mutex_lock(&mutex1);
fp1<<out1.str();
pthread_mutex_unlock(&mutex1);

在主要功能中我得到了预期的结果

53674444272163,T35,1
53674444562178,T35,2
53674444563927,T35,3
53674444565225,T35,4

而当我把

   pthread_mutex_lock(&mutex1);
   fp1<<out1.str();
   pthread_mutex_unlock(&mutex1);

我收到同样的声明(53674444272163,T35,1)打印了NTHREAD次。(53674444562178,T35,2)打印了NTHREAD次。

根据我的理解,我得到的输出是因为尽管每个线程只是正确地写入输出值,

53674444272163,T35,1 53674444562178,T35,2

所有线程都在退出时打印out1的值,所以我总是在NTHREAD时间打印相同的语句。

现在,我的问题是为什么我没有像我的ORIGINAL程序那样在没有互斥的情况下打印NSTREAD时间(53674444272163,T35,1)?

此外,有时根据我的ORIGINAL程序没有互斥锁我得到 26773分段错误(核心转储),而使用互斥锁时,分段错误从未发生过。为什么呢???

谢谢。

2 个答案:

答案 0 :(得分:0)

我无法在我的盒子上复制你的结果(4个核心),但我找到了一些东西:

  1. 您正在打印out1 NTHREAD次的结果(在线程的末尾)。所有线程完成后(在pthread_joins之后的main()中)只打印出out1的值

  2. 当您读取打印到fp1时,您没有在out1上放置互斥锁。如果你提出建议#1,这并不重要,但我认为我是出于教育目的而指出的。

  3. 我认为#1是你的问题。希望这会有所帮助。

答案 1 :(得分:0)

你正在指向“我”的指针。一个正在旋转的线程。当你的循环启动时,这将会发生变化。我希望奇怪的行为与你看到的有点不同,但是尝试将你传入的id更改为每个create_thread调用的新内容......就像这样:

    for(long i=0; i<NTHREADS; ++i) 
    {
        int *id = new int;
        *id = i;
        result= pthread_create(&threadid[i], NULL, threadA, (void *)id);
        if(result ==-1)
        {
            perror("Thread Creation Error: \n");
            exit(EXIT_FAILURE);
        }    

    }

这样做是为每个线程的id创建新内存,并确保main中的for循环不会更改该值,并且其他线程也无法访问。