<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>Automatic fuzzy-scheduling of threads in Google Thread Sanitizer to detect errors in multithreaded code</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Oleg Doronin</string-name>
          <email>dorooleg@niuitmo.ru</email>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Karina Dergun</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Andrey Dergachev</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Bug de- Lock-free</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>Saint Petersburg National Research University of Information Technologies</institution>
          ,
          <addr-line>Mechanics and Optics, Russian Federation</addr-line>
        </aff>
      </contrib-group>
      <abstract>
        <p>The paper discusses several options for thread schedulers that are transparently embedded in the analyzed program at the code instrumentation stage, which increases the likelihood of data race detection. In addition, the work is originally interpreted by the technique of fuzzing-testing: if the traditional fuzzing involves working with data, this study proposes considering threads as data and manipulate them with the help of either other scheduler. The race found with this technique missed by Google Thread Sanitizer proves that the approach is promising.</p>
      </abstract>
      <kwd-group>
        <kwd>Google Thread Sanitizer tection Multithreading Schedulers algorithms</kwd>
      </kwd-group>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>-</title>
      <p>
        The C++11 memory model [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ] introduces potential for data race. The search
for such races is expensive and di cult to implement, it primarily concerns
lockfree algorithms and algorithms with use complex schemes of synchronization of
threads on atomic variables ( ne-grained locking) [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ]. To detect data race in
multithreaded code it is necessary for the analyzer to "stumble" on this race.
This means that simultaneous execution of threads should be "met" on the
shared variable. Only in this situation it is possible to analyze whether such a
"meeting" is a race according to the memory model of C++11. A "meeting"
of this kind can be quite rare in normal program execution, so the tools which
increase the likelihood of such an event are in high demand and are actively
developed at present.
      </p>
      <p>
        There exist no production-ready solutions to address this problem. The Relacy
Race Detector (RRD) library [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ] [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ] is among the developments in this direction.
The library implements the functionality of thread management, but has a
number of disadvantages: no ability to change the number of threads at the time of
execution of the program, structural problems in the organization of the project,
it does not work correctly with Thread Local Storage (TLS) [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ], it does not take
into account the variability of global memory and others. A number of problems
have been xed in the work "Analiz problem v Relacy Race Detector s
posleduyushchim ustraneniem" [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ], but some shortcomings remain, namely:
{ The tool is unpopular, which limits its further promotion;
{ We need to change the code to use RRD, which takes a lot of time and e ort,
and causes potential errors;
A more popular tool is Google Thread Sanitizer (TSAN) [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ], which at the
compilation stage can intercept all calls to variables, function calls and other
expressions, but does not contain the algorithms of scheduling in itself. Results
obtained:
{ The tool for automatic fuzzy-scheduling of threads in Google Thread
Sanitizer is realized.
{ The examples found where the original version of TSAN does not nd
potential errors, but they can be found using the automatic fuzzy-scheduling
tool
{ The detailed comparative analysis of various algorithms for planning of
threads with the description of their pros and cons is provided.
2
      </p>
    </sec>
    <sec id="sec-2">
      <title>Relacy Race Detector</title>
      <p>Currently, there is an implementation that already knows how to manage thread
execution. The library in which this functionality is implemented is called RRD
(Relacy Race Detector). This library is external to the user which provides
usability, but also there are a number of disadvantages, such as: the inability to
change the number of threads at the time of execution, structural problems in
organization of the project, not correct work with TLS (thread local storage),
does not take into account the variability of global memory and other problems.</p>
      <p>Multithreading is always di cult. Implementing synchronization primitives is
even more di cult. And the most advanced synchronization primitives that use
the weak memory model are incredibly complex to understand. It is sometimes
necessary to use memory barriers because subtle synchronization is a matter
of order of magnitude of performance di erence and basic scaling capabilities
(sometimes, of course). But such low-level synchronization primitives contribute
to the appearance of errors related to memory order, which are very di cult to
x. Some time ago were developed the tool, which is called Relacy Race Detector
to help developers cope with these problems.</p>
      <p>Relacy Race Detector (RRD) is a veri cation algorithm for verifying sync
hronizations in the weak memory model. Physically it is a C++ library, which
consists only of header les, but it can test not only C++ algorithms, but also
Java, .net/CLI, x86, PowerPC, SPARC, etc.</p>
    </sec>
    <sec id="sec-3">
      <title>Google Thread Sanitizer</title>
      <p>Relacy Race Detector has a number of disadvantages. One of which is the
unpopularity of this tool, and to promote such tools is very di cult. The second
disadvantage is that you need to change your code to use RRD, and these changes
can be a lot of e ort. However, there is already a tool that has earned popularity{
Google Thread Sanitizer, it at compile time can intercept all calls to variables,
function calls, etc., but does not contain the algorithms of planning in itself.
Further work was related with improvement of algorithms of work the Google
Thread Sanitizer.</p>
      <p>One of the unpleasant kinds of multithreaded errors are data races. They are
di cult to nd and as a consequence to reproduce because there is no possibility
of observing errors during the whole testing cycle, and in working applications
they can be seen as rare unexplained failures. To nd errors in multithreaded
code, special programs are developed, one of which{Google Thread Sanitizer
(TSAN). TSAN uses a hybrid algorithm (based on the &lt;happens-before&gt; and
multiple locks). There are also special dynamic annotations in the
implementation that let you report complex synchronizations in user code.
4</p>
    </sec>
    <sec id="sec-4">
      <title>Platfroms</title>
      <p>Special mechanisms are needed to simulate thread execution. Such mechanisms
require either support from the operating system or ne-tune the processor
registers (this is not always possible due to restrictions imposed by the operating
system). Only mechanisms that require operating system support are considered
in the work, on the example of Linux. To switch threads, two mechanisms are
considered, the rst of which is based on ber (a lightweight thread running in user
mode) and the second based on Pthread (the standard of POSIX-implementation
of execution threads).
4.1</p>
      <sec id="sec-4-1">
        <title>Fiber-based implementation</title>
        <p>Fiber is a lightweight thread running in user mode. We do not need to access
the operating system to manage these threads. In user mode, it is su cient to
store the thread context that includes the processor registers, TLS (thread local
storage), and other ber information. In order to change the thread, you need to
save the context of the current executable thread, and then load the new values
into the processor registers, set TLS and additional information about the ber.</p>
        <p>The Linux operating system has built-in support for ber (makecontext /
swapcontext), which facilitates the change of threads, but does not update TLS
and has to contend with this problem separately.</p>
        <p>The main problem with implementing ber in Linux is that TLS is common
to all ber. This is actually the TLS of the main thread. One solution to this
problem is to copy TLS to the local thread structure and then overwrite the main
thread's TLS. The disadvantage of this approach is the high cost of copying.</p>
        <p>Copy TLS</p>
        <sec id="sec-4-1-1">
          <title>1 internal_memcpy(old_thread-&gt;GetTls(),</title>
        </sec>
        <sec id="sec-4-1-2">
          <title>2 reinterpret_cast&lt;const void *&gt;(tls_addr_),</title>
        </sec>
        <sec id="sec-4-1-3">
          <title>3 tls_size_);</title>
        </sec>
        <sec id="sec-4-1-4">
          <title>4 internal_memcpy(reinterpret_cast&lt;void *&gt;(tls_addr_),</title>
        </sec>
        <sec id="sec-4-1-5">
          <title>5 new_thread-&gt;GetTls(),</title>
        </sec>
        <sec id="sec-4-1-6">
          <title>6 tls_size_);</title>
          <p>The second disadvantage is not working with the following example:</p>
          <p>TLS Copy counterexample
1 thread_local int a = 0;
2 int main()
3 {
4 int *p = nullptr;
5 thread t1([&amp;]() {
6 p = &amp;a;
7 while (a != 1);
8 a = 2;
9
10
11
12
13
14
15
16
17 }
});
thread t2([&amp;]() {
while (p == nullptr);
*p = 1;
while (*p != 2);
});
t1.join(); t2.join();
cout &lt;&lt; "Finish" &lt;&lt; endl;
The problem here is that we pass a pointer to TLS from thread 1 to thread
2. And if implemented correctly, these areas will be di erent and the program
ends with a "Finish" display. When we copy TLS, we get that the TLS variable
will refer to the memory area associated with thread 2. Then, if we change the
value of the variable p, we get a local variable a owned by thread 2, which is
unexpected behavior. But in most cases TLS is not passed between threads, so
this decision justi es itself.</p>
          <p>Note that when a new thread is created it gets the values of local variables
that correspond to the values at the time of program startup. Consider the
following example:</p>
          <p>Initial TLS State
1 thread_local int a = 0;
2 int main()
3 {
4
5
6
7
8
9
10
11 });
12 t1.join();
13 }
});
t2.join();
cout &lt;&lt; a &lt;&lt; endl;
thread t1([&amp;]() {
++a;
thread t2([&amp;]() {</p>
          <p>cout &lt;&lt; a &lt;&lt; endl;
The output of the program will be 01, because the newly created thread will
have values in TLS corresponding to the moment of program startup. To do
1 movq %fs:0, %rax</p>
        </sec>
        <sec id="sec-4-1-7">
          <title>2 movq x@tpoff(%rax), %rax</title>
          <p>this, we must put TLS at the appropriate initial state when creating the thread.
Obtaining such a condition is a technical task and will not be considered.</p>
          <p>In order to avoid problems with TLS copying, we can change the pointer to
the local memory of the stream. The x64 address calculation is as follows:</p>
        </sec>
        <sec id="sec-4-1-8">
          <title>TLS Address Calculation</title>
          <p>To obtain and change TLS, the following wrappers were written:</p>
          <p>Functions for changing TLS
1 static unsigned long get_tls_addr()
2 {
3 unsigned long addr;
4 asm("mov %%fs:0, %0" : "=r"(addr));</p>
        </sec>
        <sec id="sec-4-1-9">
          <title>5 return addr;</title>
          <p>6 }</p>
        </sec>
        <sec id="sec-4-1-10">
          <title>7 static void set_tls_addr(unsigned long addr)</title>
          <p>8 {
9 asm("mov %0, %%fs:0" : "+r"(addr));
10 }</p>
          <p>Unfortunately, this implementation is not secure because the compiler can
optimize and not request TLS from the FS register, but in practice this has not been
observed. The bene ts of this implementation are xing performance issues, TLS
addresses are now truly di erent, but there is a new problem associated with
the possibility of non-correct behavior.</p>
          <p>Unfortunately ber is not possible to execute in parallel as they are actually
executed on one real operating system thread. A pthread-based approach will
be considered to correct this problem.
4.2</p>
        </sec>
      </sec>
      <sec id="sec-4-2">
        <title>Pthread-based implementation</title>
        <p>To implement a thread management platform using pthread, add a variable
to the stream context that will prevent the thread from executing. Then the
expectation of the thread execution capability will look like this:</p>
        <sec id="sec-4-2-1">
          <title>Waiting for thread on a variable</title>
        </sec>
        <sec id="sec-4-2-2">
          <title>1 while(old_thread-&gt;GetWait())</title>
          <p>2 {</p>
        </sec>
        <sec id="sec-4-2-3">
          <title>3 internal_sched_yield();</title>
          <p>4 }</p>
          <p>If we want to allow a thread to execute, we set the Wait variable for the thread to
false and it starts its execution. In the current implementation, only one thread
can work at a time, but there are ideas as to how this could be improved and
implemented in the follow-up work.</p>
          <p>Let's consider advantages and disadvantages of the described platform. The
main advantages of this platform: ability to run threads in parallel, can work
faster than ber in sequential mode, no problems with TLS.</p>
          <p>This implementation allows threads to run in parallel, so we need to set wait
= false for multiple threads. Because these threads correspond to the operating
system threads, they can be executed in parallel, which increases the speed of
the algorithm.</p>
          <p>The main disadvantage is the loss of the ability to take snapshots, because
the fork mechanism copies only one real thread. So on one-nuclear processors
can work slower than ber, because context switching occurs with the help of
OS.
5</p>
        </sec>
      </sec>
    </sec>
    <sec id="sec-5">
      <title>Scheduling algorithms</title>
      <p>5.1</p>
      <sec id="sec-5-1">
        <title>Random Scheduler</title>
        <p>Random Scheduler -the idea of the algorithm is based on random selection of
threads while the program is running. This algorithm is similar to the
operating system scheduling algorithm. However, thread-switching points remain
synchronous and are located in interesting places that maximize the probability of
nding an error.</p>
        <p>The random scheduler implementation uses a uniform distribution. The
formula of the distribution density function is as follows:
f (x) =
( b 1a ; x 2 [a; b]
[a; b] - distribution segment of the random value.</p>
        <p>Such a scheduling algorithm can be useful for its speed, low memory
consumption and the probability of quickly nding an error without even regardless
its shortcomings.</p>
      </sec>
      <sec id="sec-5-2">
        <title>Scheduler with di erent distributions of random values</title>
        <p>Scheduler with di erent distributions of random values - Such a scheduler is
partially similar to an algorithm of random planning in which there was only a
uniform distribution.</p>
        <p>The planning algorithm looks like this: We have a number of random value
generators. We add this set to a cyclic list. A circular list is a list in which the
last element has a pointer to the next element that is not empty, but points to
the rst element. Number generators of random values from 1::n, then the rst
iteration will use a 1 random value generator, on the second iteration of 2-th ...
on n-th iteration n, but already on the n + 1 we will use 1 generator random
values. We denote through the i iteration number of the algorithm pass, then the
number of the random value generator is calculated using the following formula (i
mod N ) + 1. An important note is that random value generators retain their old
state (it can be considered that every new seed launch will always be di erent).</p>
        <p>Random value generators that were used in the implementation of the
planning algorithm with di erent distributions of random values: uniform
distribution, bionomial distribution, negative bionomial distribution, geometric
distribution, poisson distribution, exponential distribution, weibull distribution, normal
distribution, lognormal distribution.</p>
        <p>If we look at the probability of nding errors, it will be more due to the fact
that the rst generator of random values corresponds to a uniform distribution
as in a random scheduler, and other generators are completely di erent from it,
which will allow us to nd new types of errors. Similarly, the locality of nding
errors is ensured by a uniform distribution, and the spread between the work of
the threads is achieved using other distributions.</p>
        <p>The main disadvantages of such a scheduler is that it can not cover all
possible cases, so there is a possibility that we will miss the error. The second
disadnvatage is that we have no criterion when the algorithm can be stopped.</p>
        <p>If to sum up the results it is possible to make a conclusion that generators of
random values are similar among themselves and that it would be necessary to
nd di erent errors ne-tuning of algorithms. But the main advantage of such
an algorithm is that it can nd errors very quickly with some probability. This
search is not only in the local area of the threads, but also takes into account
the scatter between the execution of threads.
5.3</p>
      </sec>
      <sec id="sec-5-3">
        <title>Full search scheduler</title>
        <p>Full search scheduler - the main disadvantage of schedulers based on random
value generators is that they do not cover all possible scheduling paths.
Therefore, the implementation of the scheduler algorithm was invented, which iterates
through all the variants, but with some limitations. For such a scheduler, we
make an important assumption that if we run the iteration several times on the
same sequence of threads, then all iterations will have the same execution paths
for the program. In practice, this condition is not always met, but it is rare cases.
1 procedure FullPathScheduler</p>
        <sec id="sec-5-3-1">
          <title>2 for i from 1 to CountIterations() do</title>
        </sec>
        <sec id="sec-5-3-2">
          <title>3 while not IsStopProgram do</title>
        </sec>
        <sec id="sec-5-3-3">
          <title>4 AsynYield(i)</title>
        </sec>
        <sec id="sec-5-3-4">
          <title>5 end while</title>
          <p>6 end for</p>
        </sec>
        <sec id="sec-5-3-5">
          <title>7 end procedure</title>
        </sec>
        <sec id="sec-5-3-6">
          <title>FullPathScheduler</title>
          <p>Let's consider the general structure of the algorithm on the example of the
procedure FullPathScheduler. Suppose we have some iterator i which is able to
iterate through all possible variants of threads execution (it will be considered
how it can be implemented), then we will iterate over all possible variants of
program execution line 2. At each iteration of the program execution we will
handle the calls where a change of ow can occur. In line 3, we check that the
program has not completed yet, and in line 4, we are processing an asynchronous
call to AsyncYield which allows you to change the execution thread at this point
in time.
1 procedure AsyncYield(iteration)
2 s = wait Yield(iteration)
3 if s != Nill then
4 context = GetThread(iteration[s])</p>
        </sec>
        <sec id="sec-5-3-7">
          <title>5 SysCallYield(context)</title>
          <p>6 end if</p>
        </sec>
        <sec id="sec-5-3-8">
          <title>7 end procedure</title>
        </sec>
        <sec id="sec-5-3-9">
          <title>AsyncYield</title>
          <p>Let's dwell on the description of the AsyncYield procedure. Wait type design
means that we are waiting for the asynchronous occurrence of some event, in our
example it is an opportunity to choose a thread for execution. The variable s
will be the value that corresponds to the call number of the wait function Yield.
That is, at the rst call it will be 0, at the second one, etc. This number will
be called the logical execution time of the program. If this number equals Nill it
means that the program has ended, otherwise we can request from our iterator,
which iterates through all possible combinations of thread execution number
that should be executed at the moment. Then, in line 4, we take the context of
the thread that will execute after the AsyncYield procedure completes, and in
line 5 we run it for execution.
The most di cult part of the algorithm is to learn to de ne all possible ways of
program execution. In the 1 table, the string T ime means a logical time. The
values in this row increase each time by 1 starting at 0 and up to a certain
number of n. The T id line shows the thread numbers that should be executed in
the current iteration. The Maxtid line has the maximum T id stream that could
be at a logical time i, where i any value from 0 to n. If we knew such a table and
it was static then we could use the standard algorithms to iterate through all the
combinations, (the description of the standard algorithm for iterating through
all the combinations can be found in the article or the detailed description in the
book) or add 1 to the number in the system in which each digit has a dimension
of Maxtid. In our case, the situation is complicated by the fact that can change:
n, maxtid and can still fall out incorrect combinations of threads. To get a new
iteration, add 1 from the end in the mixed number system.</p>
          <p>The ability to iterate through paths allows us to make sure that the code
is correct for all possible paths, provided that the same code statements are
executed at multiple startup with the same parameters.</p>
          <p>This approach consumes large memory resources, because at any time it is
necessary to store information about the maximum tid and the current thread. It
also has a long working time, is interpreted in terms of the number of iterations.
It is impossible to achieve a full enumeration of variants for large applications
because we are limited by computational resources. This algorithm is
recommended for small test scenarios.
5.4</p>
        </sec>
      </sec>
      <sec id="sec-5-4">
        <title>Scheduler based on full paths with oating window</title>
        <p>The main problem with the full-path scheduler is that we cannot wait for the
algorithm to complete because of the limited computational resources. In this
regard, we want to think of an algorithm that would allow to iterate through all
the variants in some local area. This algorithm was given the name "Scheduler
based on full paths with oating window"</p>
        <p>Consider the algorithm in detail. In the last step we have considered the
algorithm of full path iteration to which we will refer. Let's start some xed
window for certainty take size 3 and this window will be moved along the entire
time axis. Then inside this window we will iterate through all the variants using
the algorithm described above, and outside the window will move randomly.
Then in the local area we will be able to iterate through all possible cases, which
can help to nd new mistakes</p>
        <p>The main advantage of this algorithm is that if we choose a small window
size, we can get the nal algorithm even from a practical point of view. Therefore,
the working time of the algorithm is considered nite.</p>
        <p>This algorithm does not cover all possible ways if we compare it with the
previous example, but we can choose an in nitely large window and then it will
correspond to the previous algorithm
5.5</p>
      </sec>
      <sec id="sec-5-5">
        <title>Brute force based scheduler</title>
        <p>All the above algorithms have a lack of working time. Even a xed window
scheduler can take a long time to complete local iteration. We want to introduce
some criteria that would check the operation of all threads, but it required not
a large number of iterations (as a variant of the 64 iteration).</p>
        <p>The idea of the algorithm is as follows: At every moment we want to give the
opportunity to work all the threads that could be executed, thus it will not be
considered all possible paths, and it will be all possible states of threads, then
the number of iterations will be limited to the maximum number of threads from
all maximum quantities at some logical point in time. Variable used will store a
list of threads that have already been executed, variants a list of threads that
can be executed at a certain logical point in time. If we look at the tables 2 and
3, we will need only two iterations to iterate through all the options. After the
rst iteration in the 0th moment of time only the 0-th thread will work, and
after the second iteration all possible threads will work at this point of time,
and this is 0 and 1. If at some point in time we do not have any threads that
can be executed, a random thread is selected.
Time 0 1 2 3
used 0 1 1 0
variants 0,1 0,1 0,1 0,1</p>
        <p>Time 0 1 2 3
used 0,1 1,0 1,0 0,1
variants 0,1 0,1 0,1 0,1
The main disadvantage of this algorithm is that storing the list of threads for
each moment of time can be a costly operation, in order to reduce the amount
of memory will perform such a search for a maximum of 64 threads. And all the
information about the threads will be stored as bitmasks.</p>
        <p>From advantages it is desirable to allocate that such algorithm allows to
iterate all states of threads, that is at each moment of time will be able to
work all threads, but thus not all paths will be covered. This algorithm has a
limited number of iterations, which is easy to calculate at the time of program
execution.
6</p>
      </sec>
    </sec>
    <sec id="sec-6">
      <title>Test results</title>
      <p>Testing was conducted in several steps:
1. Using existing Tests Google Thread Sanitizer
2. Find cases for which schedulers can be useful
3. Testing the libcds library
1 std::atomic_int d;
2 int a;
3 int main()
4 {
5
6
7
8
9 }
std::thread t1([]() { ++d; ++a; ++d; });
std::thread t2([]() { ++d; ++a; ++d; });
t1.join(); t2.join();
std::cout &lt;&lt; d &lt;&lt; a &lt;&lt; std::endl;</p>
      <p>Tests provided by Google Thread Sanitizer required further re nement after
adding new functionality. Because the code can be executed multiple times, and
the TSAN tests rely on exactly one pass, only a small part of code could be
tested using existing tests.</p>
      <p>The following example was found on which TSAN does not cope:</p>
      <sec id="sec-6-1">
        <title>Data race on variable a</title>
        <p>In lines 5, 6 on the variable a there is a data race. Several thousand iterations
using the operating system scheduler did not nd this problem. All the developed
schedulers were tested on this example and each was able to detect the data race
on the variable a</p>
        <p>Let's look at an interesting example:</p>
      </sec>
      <sec id="sec-6-2">
        <title>1 std::atomic_int value { 0 };</title>
      </sec>
      <sec id="sec-6-3">
        <title>2 int main()</title>
      </sec>
      <sec id="sec-6-4">
        <title>Rare case</title>
        <p>3 {
4
5
6
7
8
9
10
11
12
13
14 }
auto f = [&amp;]() {
for (int j = 0; j &lt; 5; j++) {
auto r = value.load();
r++;
value.store(r);
};
std::thread t1(f), t2(f);
t1.join(); t2.join();
std::cout &lt;&lt; value.load() &lt;&lt; std::endl;
In two threads we will increase the value of the variable r per iterataion. The
operating system scheduler produces values ranging from 4 to 10. A scheduler
with di erent distributions of random values and a full search scheduler were
able to get all the possible value of the variable r,namely in the range of 2 to 10.
Here are the histogram frequencies:
When testing the libcds library, it is currently not found on simple data
structures such as lists of problems. But testing of the library continues, in particular
it is planned to check BronsonAVLTreeMap and EllenBintree
7</p>
      </sec>
    </sec>
    <sec id="sec-7">
      <title>Related work</title>
      <p>In the future it is planned to try the developed tool on such projects as: Google
Chrome Browser, Boost Library, Liblfds Library, research of other projects</p>
      <p>
        There are also a number of tasks for further improvements in the project:
support for correct work with mutex, handling hangs on spin lock, adding a
parallel scheduling algorithm [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ], acceleration of developed algorithms, Modeling
the order of visibility of variables [
        <xref ref-type="bibr" rid="ref9">9</xref>
        ] [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ], development of a scheduler to check the
properties of lock free algorithms
8
      </p>
    </sec>
    <sec id="sec-8">
      <title>Conclusion</title>
      <p>Various platforms and scheduling algorithms were considered in this paper. And
as a result, the following tasks were completed:</p>
      <p>Currently, there are examples where Google Thread Sanitizer does not nd
errors using the operating system scheduler, and the developed infrastructure
allows to nd missed errors. This shows that the goal is achieved, the developed
tool helps to nd errors in multithreaded code that was previously di cult to
detect.</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          1.
          <string-name>
            <surname>Batty</surname>
            <given-names>M.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Owens</surname>
            <given-names>S.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Sarkar</surname>
            <given-names>S.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Sewell</surname>
            <given-names>P.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Weber</surname>
            <given-names>T</given-names>
          </string-name>
          . Mathematizing C++ Concurrency // POPL, 2011
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          2.
          <string-name>
            <surname>Khizhinsky M. CDS C+</surname>
          </string-name>
          <article-title>+ library [Electronic Resource]</article-title>
          . - Access mode: https://github.com/khizmax/libcds, free.
          <source>Language English (access date 04.12</source>
          .
          <year>2018</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          3.
          <string-name>
            <surname>Vyukov D. Relacy Race</surname>
            <given-names>Detector</given-names>
          </string-name>
          [Electronic Resource]. - Access mode: https://github.com/dvyukov/relacy, free.
          <source>Language English (access date 15.11</source>
          .
          <year>2018</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          4.
          <string-name>
            <surname>Vyukov</surname>
            <given-names>D. RRD</given-names>
          </string-name>
          : Introduction [Electronic Resource]. - Access mode: http://www.1024cores.
          <article-title>net/home/relacy-race-detector/rrd-introduction, free</article-title>
          .
          <source>Language English (access date 25.11</source>
          .
          <year>2018</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          5.
          <string-name>
            <surname>Drepper U. ELF Handling For Thread-Local</surname>
            <given-names>Storage</given-names>
          </string-name>
          , Red Hat Inc,
          <year>2005</year>
          , 79 pages
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          6.
          <string-name>
            <surname>Doronin</surname>
            <given-names>O.V.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Kalishenko</surname>
            <given-names>E.L.</given-names>
          </string-name>
          ,
          <string-name>
            <surname>Kalishenko</surname>
            <given-names>E.L.</given-names>
          </string-name>
          <article-title>Analiz problem v Relacy Race Detector s posleduyushchim ustraneniem // Sbornik tezisov dokladov kongressa molodyh uchenyh</article-title>
          . [Electronic Resource]. - Access mode: http://kmu.ifmo.ru/collections article/7307/
          <article-title>analiz problem v Relacy Race Detector s posleduyuschim ustraneniem.htm, free</article-title>
          .
          <source>Language Russian (access date 20.11</source>
          .
          <year>2018</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          7.
          <string-name>
            <given-names>Google</given-names>
            <surname>Thread</surname>
          </string-name>
          <string-name>
            <surname>Sanitizer</surname>
          </string-name>
          [Electronic Resource]. - Access mode: https://github.com/google/sanitizers/wiki, free.
          <source>Language English (access date 20.11</source>
          .
          <year>2018</year>
          )
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          8.
          <string-name>
            <given-names>S.</given-names>
            <surname>Nagarakatte</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Burckhardt</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M. M.</given-names>
            <surname>Martin</surname>
          </string-name>
          and
          <string-name>
            <given-names>M.</given-names>
            <surname>Musuvathi</surname>
          </string-name>
          ,
          <article-title>Multicore acceleration of priority-based schedulers for concurrency bug detection</article-title>
          ,
          <source>ACM</source>
          ,
          <year>2012</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          9.
          <string-name>
            <given-names>C.</given-names>
            <surname>Lidbury</surname>
          </string-name>
          and
          <string-name>
            <given-names>A. F.</given-names>
            <surname>Donaldson</surname>
          </string-name>
          , Dynamic Race Detection for C++11,
          <string-name>
            <surname>POPL</surname>
          </string-name>
          ,
          <year>2016</year>
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>