title: How to prevent race conditions when performing one-to-one multithreading
body: <p>I am working on a program that will return a vector containing the number of factors for each number in a text file that is provided.</p>
  <pre><code>void thrMain(const std::vector&lt;long&gt;&amp; list, std::vector&lt;int&gt;&amp; result,
      const int startInd, const int endInd) {
      for (int i = startInd; (i &lt; endInd); i++) {
         result[i] = countFactors(list[i]);
      }
  }
  </code></pre>
  <p>This method splits the list into sections for the threads to operate on.</p>
  <pre><code>std::vector&lt;int&gt; getFactorCount(const std::vector&lt;long&gt;&amp; numList, const int thrCount) {
     // Create a list of threads
     std::vector&lt;std::thread&gt; thrList;
     // List of factor counts in each thread
     std::vector&lt;int&gt; countF(thrCount);
     // What each thread should work on
     const int thrCounter = (numList.size() / thrCount) + 1;
     // Thread work
     for (int i = 0, start = 0; (i &lt; thrCounter); i++, start += thrCounter) {
         int end = std::min&lt;int&gt;(start + thrCounter, numList.size());
         thrList.push_back(std::thread(thrMain, std::ref(numList),
              std::ref(countF), start, end));
     }
     // Join threads together once they finish
     for (auto&amp; t : thrList) {
         t.join();
     }
     return countF;
  }
  </code></pre>
  <p>The error that I get</p>
  <pre><code>==4100441==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000074 at pc 0x561fb6172859 bp 0x7f5d13c05bc0 sp 0x7f5d13c05bb0
  WRITE of size 4 at 0x602000000074 thread T2
      #0 0x561fb6172858 in thrMain(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, std::vector&lt;int, std::allocator&lt;int&gt; &gt;&amp;, int, int) /home/blackemr/cse381/exercise8_part2/exercise8_part2.cpp:27
      #1 0x561fb617c48b in void std::__invoke_impl&lt;void, void (*)(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, std::vector&lt;int, std::allocator&lt;int&gt; &gt;&amp;, int, int), std::reference_wrapper&lt;std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&gt;, std::reference_wrapper&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt;, int, int&gt;(std::__invoke_other, void (*&amp;&amp;)(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, std::vector&lt;int, std::allocator&lt;int&gt; &gt;&amp;, int, int), std::reference_wrapper&lt;std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&gt;&amp;&amp;, std::reference_wrapper&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt;&amp;&amp;, int&amp;&amp;, int&amp;&amp;) /usr/include/c++/9/bits/invoke.h:60
      #2 0x561fb617c236 in std::__invoke_result&lt;void (*)(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, std::vector&lt;int, std::allocator&lt;int&gt; &gt;&amp;, int, int), std::reference_wrapper&lt;std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&gt;, std::reference_wrapper&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt;, int, int&gt;::type std::__invoke&lt;void (*)(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, std::vector&lt;int, std::allocator&lt;int&gt; &gt;&amp;, int, int), std::reference_wrapper&lt;std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&gt;, std::reference_wrapper&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt;, int, int&gt;(void (*&amp;&amp;)(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, std::vector&lt;int, std::allocator&lt;int&gt; &gt;&amp;, int, int), std::reference_wrapper&lt;std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&gt;&amp;&amp;, std::reference_wrapper&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt;&amp;&amp;, int&amp;&amp;, int&amp;&amp;) /usr/include/c++/9/bits/invoke.h:95
      #3 0x561fb617c036 in void std::thread::_Invoker&lt;std::tuple&lt;void (*)(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, std::vector&lt;int, std::allocator&lt;int&gt; &gt;&amp;, int, int), std::reference_wrapper&lt;std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&gt;, std::reference_wrapper&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt;, int, int&gt; &gt;::_M_invoke&lt;0ul, 1ul, 2ul, 3ul, 4ul&gt;(std::_Index_tuple&lt;0ul, 1ul, 2ul, 3ul, 4ul&gt;) /usr/include/c++/9/thread:244
      #4 0x561fb617bf4f in std::thread::_Invoker&lt;std::tuple&lt;void (*)(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, std::vector&lt;int, std::allocator&lt;int&gt; &gt;&amp;, int, int), std::reference_wrapper&lt;std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&gt;, std::reference_wrapper&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt;, int, int&gt; &gt;::operator()() /usr/include/c++/9/thread:251
      #5 0x561fb617beb7 in std::thread::_State_impl&lt;std::thread::_Invoker&lt;std::tuple&lt;void (*)(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, std::vector&lt;int, std::allocator&lt;int&gt; &gt;&amp;, int, int), std::reference_wrapper&lt;std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&gt;, std::reference_wrapper&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt;, int, int&gt; &gt; &gt;::_M_run() /usr/include/c++/9/thread:195
      #6 0x7f5d173e4cb3  (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd6cb3)
      #7 0x7f5d174f8608 in start_thread /build/glibc-YYA7BZ/glibc-2.31/nptl/pthread_create.c:477
      #8 0x7f5d17223102 in __clone (/lib/x86_64-linux-gnu/libc.so.6+0x122102)
  
  0x602000000074 is located 4 bytes inside of 8-byte region [0x602000000070,0x602000000078)
  freed by thread T0 here:
      #0 0x7f5d176228df in operator delete(void*) (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x1108df)
      #1 0x561fb617804f in __gnu_cxx::new_allocator&lt;std::thread&gt;::deallocate(std::thread*, unsigned long) /usr/include/c++/9/ext/new_allocator.h:128
      #2 0x561fb6176e45 in std::allocator_traits&lt;std::allocator&lt;std::thread&gt; &gt;::deallocate(std::allocator&lt;std::thread&gt;&amp;, std::thread*, unsigned long) /usr/include/c++/9/bits/alloc_traits.h:470
      #3 0x561fb6175dbf in std::_Vector_base&lt;std::thread, std::allocator&lt;std::thread&gt; &gt;::_M_deallocate(std::thread*, unsigned long) /usr/include/c++/9/bits/stl_vector.h:351
      #4 0x561fb6177b78 in void std::vector&lt;std::thread, std::allocator&lt;std::thread&gt; &gt;::_M_realloc_insert&lt;std::thread&gt;(__gnu_cxx::__normal_iterator&lt;std::thread*, std::vector&lt;std::thread, std::allocator&lt;std::thread&gt; &gt; &gt;, std::thread&amp;&amp;) /usr/include/c++/9/bits/vector.tcc:500
      #5 0x561fb6176978 in void std::vector&lt;std::thread, std::allocator&lt;std::thread&gt; &gt;::emplace_back&lt;std::thread&gt;(std::thread&amp;&amp;) /usr/include/c++/9/bits/vector.tcc:121
      #6 0x561fb6175355 in std::vector&lt;std::thread, std::allocator&lt;std::thread&gt; &gt;::push_back(std::thread&amp;&amp;) /usr/include/c++/9/bits/stl_vector.h:1201
      #7 0x561fb6172d26 in getFactorCount(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, int) /home/blackemr/cse381/exercise8_part2/exercise8_part2.cpp:53
      #8 0x561fb617397e in main /home/blackemr/cse381/exercise8_part2/exercise8_part2.cpp:126
      #9 0x7f5d171280b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
  
  previously allocated by thread T0 here:
      #0 0x7f5d17621947 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10f947)
      #1 0x561fb617a66c in __gnu_cxx::new_allocator&lt;std::thread&gt;::allocate(unsigned long, void const*) /usr/include/c++/9/ext/new_allocator.h:114
      #2 0x561fb617985f in std::allocator_traits&lt;std::allocator&lt;std::thread&gt; &gt;::allocate(std::allocator&lt;std::thread&gt;&amp;, unsigned long) /usr/include/c++/9/bits/alloc_traits.h:444
      #3 0x561fb617876d in std::_Vector_base&lt;std::thread, std::allocator&lt;std::thread&gt; &gt;::_M_allocate(unsigned long) /usr/include/c++/9/bits/stl_vector.h:343
      #4 0x561fb61778e7 in void std::vector&lt;std::thread, std::allocator&lt;std::thread&gt; &gt;::_M_realloc_insert&lt;std::thread&gt;(__gnu_cxx::__normal_iterator&lt;std::thread*, std::vector&lt;std::thread, std::allocator&lt;std::thread&gt; &gt; &gt;, std::thread&amp;&amp;) /usr/include/c++/9/bits/vector.tcc:440
      #5 0x561fb6176978 in void std::vector&lt;std::thread, std::allocator&lt;std::thread&gt; &gt;::emplace_back&lt;std::thread&gt;(std::thread&amp;&amp;) /usr/include/c++/9/bits/vector.tcc:121
      #6 0x561fb6175355 in std::vector&lt;std::thread, std::allocator&lt;std::thread&gt; &gt;::push_back(std::thread&amp;&amp;) /usr/include/c++/9/bits/stl_vector.h:1201
      #7 0x561fb6172d26 in getFactorCount(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, int) /home/blackemr/cse381/exercise8_part2/exercise8_part2.cpp:53
      #8 0x561fb617397e in main /home/blackemr/cse381/exercise8_part2/exercise8_part2.cpp:126
      #9 0x7f5d171280b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
  
  Thread T2 created by T0 here:
      #0 0x7f5d1754c805 in pthread_create (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x3a805)
      #1 0x7f5d173e4f78 in std::thread::_M_start_thread(std::unique_ptr&lt;std::thread::_State, std::default_delete&lt;std::thread::_State&gt; &gt;, void (*)()) (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0xd6f78)
      #2 0x561fb6172d10 in getFactorCount(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, int) /home/blackemr/cse381/exercise8_part2/exercise8_part2.cpp:53
      #3 0x561fb617397e in main /home/blackemr/cse381/exercise8_part2/exercise8_part2.cpp:126
      #4 0x7f5d171280b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
  
  SUMMARY: AddressSanitizer: heap-use-after-free /home/blackemr/cse381/exercise8_part2/exercise8_part2.cpp:27 in thrMain(std::vector&lt;long, std::allocator&lt;long&gt; &gt; const&amp;, std::vector&lt;int, std::allocator&lt;int&gt; &gt;&amp;, int, int)
  Shadow bytes around the buggy address:
    0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  =&gt;0x0c047fff8000: fa fa fd fa fa fa fd fd fa fa 00 fa fa fa[fd]fa
    0x0c047fff8010: fa fa fd fd fa fa fa fa fa fa fa fa fa fa fa fa
    0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  Shadow byte legend (one shadow byte represents 8 application bytes):
    Addressable:           00
    Partially addressable: 01 02 03 04 05 06 07 
    Heap left redzone:       fa
    Freed heap region:       fd
    Stack left redzone:      f1
    Stack mid redzone:       f2
    Stack right redzone:     f3
    Stack after return:      f5
    Stack use after scope:   f8
    Global redzone:          f9
    Global init order:       f6
    Poisoned by user:        f7
    Container overflow:      fc
    Array cookie:            ac
    Intra object redzone:    bb
    ASan internal:           fe
    Left alloca redzone:     ca
    Right alloca redzone:    cb
    Shadow gap:              cc
  ==4100441==ABORTING
  </code></pre>
  <p>I have tried changing the thread counter formula and my next idea is to use a mutex, is a mutex the correct way to prevent Race Conditions?</p>