2

The output generated by my code is ambiguous.

int main()
{

    cout << "THIS IS AN THREADING EXAMPLE IN C++" << endl;
    cout<<"MAIN , reverse and forward are executed"<<endl;
    thread rev_thread(print_reverse,1);
    thread for_thread(print_forwward,1);
    rev_thread.join();
    for_thread.join();
    cout << "AIN , reverse and forward are DONE" << endl;
    return 0;
}
    void print_reverse(int wait_sec)
    {
       for(int rev=5000;rev>=1;rev--)
    {
    //std::this_thread::sleep_for (std::chrono::seconds(wait_sec));
     cout<<"The rev ::" << rev<<endl;

    }
    }
void print_forwward(int wait_sec)
{
    for(int forw=1;forw<=5000;forw++)
    {
    //std::this_thread::sleep_for (std::chrono::seconds(wait_sec));
    cout<<"The forward ::" << forw<<endl;

    }
}

I am expecting a mix of print_forwward and print_reverse in any random manner **

But here is what i am getting :-
The rev ::4997

The rev ::4996
The rev ::4995
The rev ::4994
The rev ::4993
The rev ::4992
The rev ::4991
The rev ::4990
The rev ::4989
The rev ::4988
The rev ::4987
The rev ::4986

The forward ::2
The forward ::3
The forward ::4
The forward ::5
The forward ::6
The forward ::7
The forward ::8
The rev ::4985
The rev ::4984
The rev ::4983
The rev ::4982
The rev ::4981
The forward ::The rev ::4980
The rev ::4979
9The rev ::4978
The rev ::4977
The rev ::4976

The forward ::10
The forward ::11
The forward ::12
The forward ::13
The forward ::14
The rev ::The forward ::15
The forward ::16
4975The forward ::17
The forward ::18
The forward ::19
The forward ::20
The forward ::21
The forward ::22

The rev ::The forward ::234974
The forward ::24
The forward ::25

what is 234974 all about?? and moreover the print rev and forward in one line??!!
Please notice the gaps are also printed in the same way as output!
Here I have commented out the wait for testing
Please note I am new to this concept.
Any help will be highly appreciated

Archiac Coder
  • 156
  • 2
  • 13

2 Answers2

2

C++ operator << for streams is not "thread safe"; with that I mean that nothing prevents the control to switch between threads in the middle of an expression like std::cout << x << y; between the output of x and the output of y.

What you are seeing is a 23 immediately follower by a 4974.

Unfortunately because of the sad interface defined by the operator it's also not trivial to make it "thread safe" (not impossible, but annoyingly hard).

Actually a string format approach à la printf works much better (also) for this.

6502
  • 112,025
  • 15
  • 165
  • 265
  • Thanks alot!! I refered : http://www.cplusplus.com/reference/thread/thread/ and http://www.cplusplus.com/reference/thread/thread/join/ and thought of giving it a try .I got that working with printf as expected. Please let me know if any other resource for leaning multithreading in c++. IS there any other way than printf ?? – Archiac Coder Apr 21 '19 at 18:48
  • See also .. https://stackoverflow.com/a/39092171/2785528. printf is also not 'thread safe'. – 2785528 Apr 23 '19 at 19:52
  • @2785528: `printf` is not guaranteed thread safe (and I didn't say it is), but it is simple to implement it thread safe and it's actually often implemented thread safe. The problem with the stream operators is that it's much more annoying to implement them thread safe, so implementers simply don't. In general implementing an output facility (e.g. for logging) based on format strings (à la `printf`) and thread-safe is easy. With streams is harder because the **interface** is broken on many levels. – 6502 Apr 23 '19 at 22:36
1

what is 234974 all about?? and moreover the print rev and forward in one line??!! Please notice the gaps are also printed in the same way as output! Here I have commented out the wait for testing Please note I am new to this concept. Any help will be highly appreciated


It is clear to me that your 'mix' of outputs did occur, just somewhat more interstingly or differently than you expected. I have found this kind of 'interrupted' / 'interleaved' output (on serial devices) even in real time OS's.

I am expecting a mix of print_forwward and print_reverse in any random manner **

Reasonable. But you have not identified the OS you are running on, nor how many cores might be active, both can contribute to or change your results.

I think it is fine to tolerate the issue (of cout's lack-of-thread-safety) by using a mutex so that only 1 thread can cout at a time.

The easiest refactor might be a mutex lock() in front and an unlock() after each cout (in the for loops).


You might consider replacing the cout-of-a-value, with a push-of-a-value into a large vector. Yes, the vectors required mutex access also, but because memory based, the push should be much faster than a cout. (sorry, I've not yet measured.)

In my experiment, 10 (default) threads (on a 2 core hw) push values into a vector (init with reserve of 50 million) for a duration of 10 seconds. After the 'race' to fill the vector was complete, a single thread cout'd the vector contents to a file for later analysis (latest test content about 37 million chars. a brief report says the code spent about 3 seconds to write the vector contents to a text file.)

writing ID sequence of 31,862,791 values to ./Q6.txt
complete: 2,968,610 us

The (arbitrary) 10 second duration was measured by thread-main doing mostly nothing while the 10 threads ran. The following snippet is used between the launch and join of the threads, and also produces a 'progress cout' (as the other threads are not using cout)

// threads start

// progress indicator to user
for (size_t i = 0; i < MaxSecs; ++i) // let threads switch for 10 seconds
{
    sleepToWallClockStartOfSec();    // 'main()' sync's to wall clock
    cout << (MaxSecs-i-1) << ' ' << flush; // "9 8 7 6 5 4 3 2 1 0"
}
m_done = true;  // command threads to exit - all threads can see m_done

// threads joins

Linux surprised me ... by how few context switches were completed.

2785528
  • 5,438
  • 2
  • 18
  • 20
  • While not appropriate for this post ... out of 31,862,791 thread-entries through the critsect, there were only 24,266,264 full context switches occurred. Hmmm. Interesting. More research needed. – 2785528 Apr 21 '19 at 21:33
  • Thank for in depth explanation ! I will surely try with these ideas too.Bdw i am using ubuntu i5 8 gen. – Archiac Coder Apr 23 '19 at 07:12
  • Back a decade or so, (during my telecomm experience, before c++11), printf was much more used than cout. I can report that this same 'interleave' happens with printf, probably for the same reason (i.e. not thread safe). Even on real-time os (like OSE or vxWorks) The general idea of cout'ing a completed string (such as sending the stringstream::str() ) is easy to achieve in C++. – 2785528 Apr 23 '19 at 13:40
  • see also: https://stackoverflow.com/a/39092171/2785528 std::printf also not 'thread safe' – 2785528 Apr 23 '19 at 19:52