Remember to join

When I forget to join (or detach) a C++ std::thread, it’ll crash with SIGABRT(6) on macOS. And obviously the stack dump does not tell me what is going on. So I hunt the bug for some hours, digging the log files, then finally remember that I just implemented a thread…

***** FATAL SIGNAL RECEIVED *******
Received fatal signal: SIGABRT(6)	PID: 17403

***** SIGNAL SIGABRT(6)

*******	STACKDUMP *******
	stack dump [1]  1   libg3logger.1.3.2-80.dylib          0x0000000100cb2163 _ZN12_GLOBAL__N_113signalHandlerEiP9__siginfoPv + 83
	stack dump [2]  2   libsystem_platform.dylib            0x00007fff72f73b1d _sigtramp + 29
	stack dump [3]  3   ???                                 0x0000000000000400 0x0 + 1024
	stack dump [4]  4   libsystem_c.dylib                   0x00007fff72e49a1c abort + 120
	stack dump [5]  5   libc++abi.dylib                     0x00007fff6fef2bc8 __cxa_bad_cast + 0
	stack dump [6]  6   libc++abi.dylib                     0x00007fff6fef2ca6 _ZL28demangling_terminate_handlerv + 48
	stack dump [7]  7   libc++abi.dylib                     0x00007fff6feffda7 _ZSt11__terminatePFvvE + 8
	stack dump [8]  8   libc++abi.dylib                     0x00007fff6feffd68 _ZSt9terminatev + 56
	stack dump [9]  9   BasicInfoGUI                        0x0000000100af1ffa _ZN11OHARStudent14StudentHandler8readFileEv + 42
	stack dump [10]  10  BasicInfoGUI                        0x0000000100af28df _ZN11OHARStudent14StudentHandler7consumeERN8OHARBase7PackageE + 2223
	stack dump [11]  11  BasicInfoGUI                        0x0000000100a6d101 _ZN8OHARBase13ProcessorNode14passToHandlersERNS_7PackageE + 897
	stack dump [12]  12  BasicInfoGUI                        0x0000000100a6a69e _ZN8OHARBase13ProcessorNode10threadFuncEv + 2462
	stack dump [13]  13  BasicInfoGUI                        0x0000000100a79061 _ZNSt3__1L8__invokeIMN8OHARBase13ProcessorNodeEFvvEPS2_JEvEEDTcldsdeclsr3std3__1E7forwardIT0_Efp0_Efp_spclsr3std3__1E7forwardIT1_Efp1_EEEOT_OS6_DpOS7_ + 113
	stack dump [14]  14  BasicInfoGUI                        0x0000000100a78f6e _ZNSt3__1L16__thread_executeINS_10unique_ptrINS_15__thread_structENS_14default_deleteIS2_EEEEMN8OHARBase13ProcessorNodeEFvvEJPS7_EJLm2EEEEvRNS_5tupleIJT_T0_DpT1_EEENS_15__tuple_indicesIJXspT2_EEEE + 62
	stack dump [15]  15  BasicInfoGUI                        0x0000000100a78796 _ZNSt3__114__thread_proxyINS_5tupleIJNS_10unique_ptrINS_15__thread_structENS_14default_deleteIS3_EEEEMN8OHARBase13ProcessorNodeEFvvEPS8_EEEEEPvSD_ + 118
	stack dump [16]  16  libsystem_pthread.dylib             0x00007fff72f7ed36 _pthread_start + 125
	stack dump [17]  17  libsystem_pthread.dylib             0x00007fff72f7b58f thread_start + 15

Exiting after fatal event  (FATAL_SIGNAL). Fatal type:  SIGABRT
Log content flushed sucessfully to sink

So I am writing this down, just to remember next time. Join or detach. Join or detach….

   void StudentHandler::readFile() {
      std::thread( [this] {
         StudentFileReader reader(*this);
         using namespace std::chrono_literals;
         std::this_thread::sleep_for(50ms);
         reader.read(node.getDataFileName());
      }).join();
   }

Edit: Actually, I changed join() to detach(). With join, the calling thread waited for this file reading thread to finish before continuing to handle incoming data from network. The file was read totally in memory, and only then data from network was combined with data from file and send ahead to next node in the network. With 5000 test records, all of them were held in memory waiting for the data from network to arrive when using join().

When I switched to use detach(), calling thread could continue reading data from network, while simultaneously file reading thread was reading data from file. Whenever a match was found in a list, either one of these threads, the data was combined and send ahead to the next node in the network. So with join, maximum of 5000 records were held in memory all the time, as with detach(), about 1300-1800 records were held in memory at most. Because combined data could be send ahead to next node in the network and discarded from this node. A significant change in the amount of memory the nodes use. So it does matter which you use, depending on the purpose of the threads in your app.