Writing data write records from std :: set insert () and find ()?

To experiment with thread disinfectant, I created a tiny C ++ program that contains a data race for its intended purpose. Indeed, Zang discovers a mistake, great! However, I am puzzled by the post created ...

  • A write-write race is reported where I would expect a read-write race. I would hope that I would find()not write in my container. If I make a slight adjustment to the code, trying to get the version const set::find(), then it seems that the previous write-write race remains.
  • It shows a write conflict between a 4-byte atomic write and an 8-byte write at the same address. It seems strange that two such different types of access are accessed by the same field in the container class.

Is it possible to use const find(), which is not written to the STL container?

This is a proven C ++ program:

/*****************************************************************************
 * Small example with an inter-thread data race that is not obvious.
 * the error is a consequence of the non-threadsafeness of the STL containers.
 * Threading is created through portable C++11 constructs.
 * Tsan does detect the data race(?).
 *
 * Compile with one of:
 * g++-4.8 -std=c++11 -g -Wall -o race-stl11b race-stl11b.cc -pthread
 * g++-4.8 -std=c++11 -g -Wall -fsanitize=thread -fPIE -o race-stl11b-tsan race-stl11b.cc -ltsan -pie -pthread
 ******************************************************************************/

#include <iostream>
#include <thread>
#include <set>

int main()
{
    // create an empty bucket
    std::set<int> bucket;

    // Use a background task to insert value '5' in the bucket 
    std::thread t([&](){ bucket.insert(5); });

    // Check if value '3' is in the bucket (not expected :-)
    bool contains3 = bucket.find(3) != bucket.cend();
    std::cout << "Foreground find done: " << contains3 << std::endl;

    // Wait for the background thread to finish
    t.join();

    // verify that value '5' did arrive in the bucket
    bool contains5 = bucket.find(5) != bucket.cend();
    std::cout << "Background insert: " << contains5 << std::endl;

    return 0;
}

And this (part) of the central nervous system conclusion:

WARNING: ThreadSanitizer: data race (pid=21774)                                                                                               

  Write of size 8 at 0x7d080000bfc8 by thread T1:                                                                                             
    #0 <null> <null>:0 (libtsan.so.0+0x00000001e2c0)                                                                                          
    #1 deallocate /usr/include/c++/4.8/ext/new_allocator.h:110 (exe+0x000000002a79)                                                           
    #2 deallocate /usr/include/c++/4.8/bits/alloc_traits.h:377 (exe+0x000000002962)                                                           
    #3 _M_destroy /usr/include/c++/4.8/bits/shared_ptr_base.h:417 (exe+0x00000000306b)                                                        
    #4 <null> <null>:0 (libstdc++.so.6+0x0000000b5f8a)                                                                                        

  Previous atomic write of size 4 at 0x7d080000bfc8 by main thread:
    #0 <null> <null>:0 (libtsan.so.0+0x00000000da45)
    #1 __exchange_and_add /usr/include/c++/4.8/ext/atomicity.h:49 (exe+0x000000001c9f)
    #2 __exchange_and_add_dispatch /usr/include/c++/4.8/ext/atomicity.h:82 (exe+0x000000001d56)
    #3 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/4.8/bits/shared_ptr_base.h:141 (exe+0x00000000390d)
    #4 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/4.8/bits/shared_ptr_base.h:553 (exe+0x00000000363c)
    #5 std::__shared_ptr<std::thread::_Impl_base, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/4.8/bits/shared_ptr_base.h:810
 (exe+0x00000000351b)
    #6 std::shared_ptr<std::thread::_Impl_base>::~shared_ptr() /usr/include/c++/4.8/bits/shared_ptr.h:93 (exe+0x000000003547)
    #7 thread<main()::__lambda0> /usr/include/c++/4.8/thread:135 (exe+0x0000000020c3)
    #8 main /home/......./race-stl11b.cc:22 (exe+0x000000001e38)

Thanks for any feedback, Jos

+4
source share
1 answer

It seems that ThreadSanitizer gives you a false positive in the implementation of std :: thread.

Reducing your example so as not to perform any given manipulations, for example:

#include <iostream>
#include <thread>
#include <set>

int main()
{
    std::set<int> bucket;
    std::thread t([&](){ /*bucket.insert(5);*/ });
    t.join();

    return 0;
}

Shows the same error in ThreadSanitizer.

Note that ThreadSanitizer does NOT search read and write status.

+1
source

Source: https://habr.com/ru/post/1530619/


All Articles