summaryrefslogtreecommitdiffstats
path: root/library/cpp/containers/cow_string/ut_medium/cow_string_medium_ut.cpp
blob: a9a37db776dc1b301e3d4f5e1774ed1a6d5e3acb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <library/cpp/containers/cow_string/cow_string.h>

#include <library/cpp/testing/unittest/registar.h>

#include <util/generic/strbuf.h>
#include <util/generic/yexception.h>
#include <util/stream/output.h>
#include <util/system/thread.h>

#include <string>
#include <barrier>

static_assert(sizeof(TCowString) == sizeof(const char*), "expect sizeof(TCowString) == sizeof(const char*)");

Y_UNIT_TEST_SUITE(CowPitfalls) {
    Y_UNIT_TEST(ParallelDetach) {
        // best results with thread-sanitizer
        std::vector<std::unique_ptr<TThread>> threads;
        TCowString a = "the string";
        TCowString b = a;
        auto makeRefToA = [&a, &b]() {
            b = a; // make second reference to the same string
        };
        constexpr int nThreads = 8;
#ifdef _tsan_enabled_
        constexpr i64 retries = 1'000;
#else
        constexpr i64 retries = 1'000'000;
#endif
        std::barrier iterationSyncPoint(nThreads, makeRefToA);
        std::atomic<i64> totalLen = 0;
        auto addLen = [](std::string a, std::atomic<i64>& len) {
            len += a.length();
        };
        auto workload = [&a, &addLen, &totalLen, &iterationSyncPoint]() {
            std::atomic<i64> len = 0;
            for (i64 j = 0; j < retries; ++j) {
                addLen(a, len); // possibility of bad implicit conversion
                iterationSyncPoint.arrive_and_wait();
            }
            totalLen += len.load();
        };
        for (int i = 0; i < nThreads; ++i) {
            threads.push_back(std::make_unique<TThread>(workload));
        }
        for (auto& t : threads) {
            t->Start();
        }
        for (auto& t : threads) {
            t->Join();
        }
        UNIT_ASSERT_VALUES_EQUAL(totalLen.load(), b.size() * nThreads * retries);
    }

} // Y_UNIT_TEST_SUITE(CowPitfalls)