线程安全地用多线程写入c ++中的流

时间:2014-04-01 14:31:47

标签: c++ linux multithreading performance-testing

我正在尝试创建多个线程并尝试找出调度顺序以及何时完成。 每次一个线程获得CPU它执行一些计算,然后它等待一些x时间(1000ns)作为忙等待 然后去睡觉每当一个线程获得CPU时,它也会打印时间,以便我以后可以找到它 特定线程获得CPU和订单的时间。

为了使线程安全,我使用的是互斥锁,但它仍然没有给出正确的结果。 我在哪里犯错误?任何帮助将受到高度赞赏。

我在linux下使用g ++。

注意:我无法使用文件,因为文件打开/关闭会导致开销。

这是我的程序输出

Output :

$ sort -t , -k4,4n -k5,5n -k6,6n >a.txt
$ head a.txt 
thread,   thread_no, iteration, time_min, time_sec, time_microsec    
foo,
foo,14,987
foo,32
foo,32,985,
foo,57,970
foo,71,933,
foo,71,933,
foo,71,933,
foo,71,933,

$ tail a.txt  
thread,   thread_no, iteration, time_min, time_sec, time_microsec
foo,98,991,40,05,935379 
foo,98,992,40,05,935442 
foo,98,993,40,05,935506 
foo,98,994,40,05,935569 
foo,98,995,40,05,935633 
foo,98,996,40,05,935697 
foo,98,997,40,05,935760 
foo,98,998,40,05,935824 
foo,98,999,40,05,937914 
foo,98,1000,40,05,937994

根据Bart van Nierop在发布互斥锁之前添加.flush()的评论,

这是结果。$ head a.txt

foo,
foo,
foo,48,991,
foo,65,
foo,95,
foo,97
foo,10,1,15,59,288329 
foo,10,1,15,59,288329 
foo,10,1,15,59,288329

这是我的计划

#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>

#define BILLION  1000000000L
#define NUM_THREADS 100

std::mutex mtx;           // mutex for critical section

using namespace std;


std::string now_str()
{
    struct timeval tv;
    struct timezone tz;
    struct tm *tm;
    gettimeofday(&tv, &tz);
    tm=localtime(&tv.tv_sec);
    char buf[40];
    sprintf(buf,"%02d,%02d,%ld ", tm->tm_min,tm->tm_sec, tv.tv_usec); 
    return buf;
}


std::ostringstream out;  
/* This is our thread function.  It is like main(), but for a thread*/
void *threadFunc(void *arg)
{ 
      int s,j;
      pthread_attr_t gattr;

      // Assigning SCHED_RR policy 

      j = SCHED_RR;
      s = pthread_attr_setschedpolicy(&gattr, j);
      if (s != 0) 
        printf( "pthread_attr_setschedpolicy");

      s = pthread_attr_getschedpolicy(&gattr, &j);
      if (s != 0)
        printf( "pthread_attr_getschedpolicy");


    struct timespec start, stop;
    double accum;

    char *str;
    int i = 0,k=0;

    str=(char*)arg;

    while(i < 1000)
    {

        ++i;

        // do something here

        mtx.lock(); 
        out << "\nfoo," <<str<<","<<i<<"," <<now_str(); // note the timing of thread
        mtx.unlock();  


    if( clock_gettime( CLOCK_REALTIME, &start) == -1 ) 
    {
          perror( "clock gettime" );
          exit( EXIT_FAILURE );
    }

    // busy wait for 1000ns
    do

    { 
        if( clock_gettime( CLOCK_REALTIME, &stop) == -1 ) 
        {
              perror( "clock gettime" );
              exit( EXIT_FAILURE );
            }

        accum = ( stop.tv_sec - start.tv_sec )* BILLION + ( stop.tv_nsec - start.tv_nsec ) ;

    }while(accum < 1000);

        // block the thread, to allow other thread to run
        usleep(1);
    }
    std::cout<<out.str();

    return NULL;
}

int main(void)
{

    pthread_t pth[NUM_THREADS];  
    int i = 0;
pthread_create(&pth[0],NULL, threadFunc,  (void *) "0"); 
pthread_create(&pth[1],NULL, threadFunc,  (void *) "1"); 
.
.
.

pthread_create(&pth[98],NULL, threadFunc,  (void *) "98"); 
pthread_create(&pth[99],NULL, threadFunc,  (void *) "99"); 

    for(int k=0;k<NUM_THREADS;k++)
    pthread_join(pth[k],NULL);

    return 0;
}

2 个答案:

答案 0 :(得分:4)

您在填充std::ostringstream out时持有互斥锁,但在将其流式传输到std::cout时却没有。因此,持有互斥锁的一个线程可以同时突变out而另一个没有互斥锁从中读取它。

最简单的解决方法是使用相同的互斥锁保护您的std::cout<<out.str();行。

如果你关心性能,你可以使全局std::ostringstream out成为一个函数局部变量(我不知道为什么你首先有这么多全局变量),所以每个线程都有它的自己的副本。然后,虽然您仍应保护全局cout,但您不需要使用互斥体来格式化自己的流。

答案 1 :(得分:0)

在谷歌上搜索一下,它看起来像ostringstream is not thread safe

要获得您想要的内容,您可以自行编辑日志。

一种方法是写入大缓冲区的末尾:

uint64_t offset = 0;
char buffer[ 200000 ];

使用互斥锁写入:

mtx.lock(); 
offset += sprintf( buffer + offset, "\nfoo,%s,%d,%s", str, i, now_str().c_str() );
mtx.unlock();