<?xml version="1.0" encoding="UTF-8"?>
<TEI xml:space="preserve" xmlns="http://www.tei-c.org/ns/1.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://www.tei-c.org/ns/1.0 https://raw.githubusercontent.com/kermitt2/grobid/master/grobid-home/schemas/xsd/Grobid.xsd"
 xmlns:xlink="http://www.w3.org/1999/xlink">
	<teiHeader xml:lang="en">
		<fileDesc>
			<titleStmt>
				<title level="a" type="main">Automatic fuzzy-scheduling of threads in Google Thread Sanitizer to detect errors in multithreaded code</title>
			</titleStmt>
			<publicationStmt>
				<publisher/>
				<availability status="unknown"><licence/></availability>
			</publicationStmt>
			<sourceDesc>
				<biblStruct>
					<analytic>
						<author>
							<persName><forename type="first">Oleg</forename><surname>Doronin</surname></persName>
							<affiliation key="aff0">
								<orgName type="department">Mechanics and Optics</orgName>
								<orgName type="institution">Saint Petersburg National Research University of Information Technologies</orgName>
								<address>
									<country key="RU">Russian Federation</country>
								</address>
							</affiliation>
						</author>
						<author>
							<persName><forename type="first">Karina</forename><surname>Dergun</surname></persName>
							<affiliation key="aff0">
								<orgName type="department">Mechanics and Optics</orgName>
								<orgName type="institution">Saint Petersburg National Research University of Information Technologies</orgName>
								<address>
									<country key="RU">Russian Federation</country>
								</address>
							</affiliation>
						</author>
						<author>
							<persName><forename type="first">Andrey</forename><surname>Dergachev</surname></persName>
							<affiliation key="aff0">
								<orgName type="department">Mechanics and Optics</orgName>
								<orgName type="institution">Saint Petersburg National Research University of Information Technologies</orgName>
								<address>
									<country key="RU">Russian Federation</country>
								</address>
							</affiliation>
						</author>
						<title level="a" type="main">Automatic fuzzy-scheduling of threads in Google Thread Sanitizer to detect errors in multithreaded code</title>
					</analytic>
					<monogr>
						<imprint>
							<date/>
						</imprint>
					</monogr>
					<idno type="MD5">FD87DBF2FD2C51E5AB76AF7163B9DC7F</idno>
				</biblStruct>
			</sourceDesc>
		</fileDesc>
		<encodingDesc>
			<appInfo>
				<application version="0.7.2" ident="GROBID" when="2023-03-24T22:42+0000">
					<desc>GROBID - A machine learning software for extracting information from scholarly documents</desc>
					<ref target="https://github.com/kermitt2/grobid"/>
				</application>
			</appInfo>
		</encodingDesc>
		<profileDesc>
			<textClass>
				<keywords>
					<term>Google Thread Sanitizer</term>
					<term>Relacy Race Detector</term>
					<term>Bug detection</term>
					<term>Multithreading</term>
					<term>Schedulers</term>
					<term>Data races</term>
					<term>Libcds</term>
					<term>Lock-free algorithms</term>
				</keywords>
			</textClass>
			<abstract>
<div xmlns="http://www.tei-c.org/ns/1.0"><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></div>
			</abstract>
		</profileDesc>
	</teiHeader>
	<text xml:lang="en">
		<body>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="1">Introduction</head><p>The C++11 memory model <ref type="bibr" target="#b0">[1]</ref> introduces potential for data race. The search for such races is expensive and difficult to implement, it primarily concerns lockfree algorithms and algorithms with use complex schemes of synchronization of threads on atomic variables (fine-grained locking) <ref type="bibr" target="#b1">[2]</ref>. 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 <ref type="bibr">[3] [4]</ref> 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) <ref type="bibr" target="#b4">[5]</ref>, it does not take into account the variability of global memory and others. A number of problems have been fixed in the work "Analiz problem v Relacy Race Detector s posleduyushchim ustraneniem" <ref type="bibr" target="#b5">[6]</ref>, but some shortcomings remain, namely:</p><p>-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 effort, and causes potential errors;</p><p>A more popular tool is Google Thread Sanitizer (TSAN) <ref type="bibr" target="#b6">[7]</ref>, 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:</p><p>-The tool for automatic fuzzy-scheduling of threads in Google Thread Sanitizer is realized.</p><p>-The examples found where the original version of TSAN does not find 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.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="2">Relacy Race Detector</head><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. Multithreading is always difficult. Implementing synchronization primitives is even more difficult. 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 difference 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 difficult to fix. 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 verification algorithm for verifying synchronizations in the weak memory model. Physically it is a C++ library, which consists only of header files, but it can test not only C++ algorithms, but also Java, .net/CLI, x86, PowerPC, SPARC, etc.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="3">Google Thread Sanitizer</head><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 difficult. The second disadvantage is that you need to change your code to use RRD, and these changes can be a lot of effort. 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 difficult to find 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 find errors in multithreaded code, special programs are developed, one of which-Google Thread Sanitizer (TSAN). TSAN uses a hybrid algorithm (based on the ¡happens-before¿ and multiple locks). There are also special dynamic annotations in the implementation that let you report complex synchronizations in user code.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="4">Platfroms</head><p>Special mechanisms are needed to simulate thread execution. Such mechanisms require either support from the operating system or fine-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 first of which is based on fiber (a lightweight thread running in user mode) and the second based on Pthread (the standard of POSIX-implementation of execution threads).</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="4.1">Fiber-based implementation</head><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 sufficient to store the thread context that includes the processor registers, TLS (thread local storage), and other fiber 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 fiber. The Linux operating system has built-in support for fiber (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 fiber in Linux is that TLS is common to all fiber. 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. 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 different 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 justifies 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><formula xml:id="formula_0">Initial TLS State thread_local int a = 0; int main() { thread t1([&amp;]() { ++a; thread t2([&amp;]() { cout &lt;&lt; a &lt;&lt; endl; }); t2.join(); cout &lt;&lt; a &lt;&lt; endl; }); t1.join(); }</formula><p>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 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><p>TLS Address Calculation movq %fs:0, %rax movq x@tpoff(%rax), %rax</p><p>To obtain and change TLS, the following wrappers were written:</p><p>Functions for changing TLS static unsigned long get_tls_addr() { unsigned long addr; asm("mov %%fs:0, %0" : "=r"(addr)); return addr; } static void set_tls_addr(unsigned long addr) { asm("mov %0, %%fs:0" : "+r"(addr)); } 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 benefits of this implementation are fixing performance issues, TLS addresses are now truly different, but there is a new problem associated with the possibility of non-correct behavior.</p><p>Unfortunately fiber 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.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="4.2">Pthread-based implementation</head><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><p>Waiting for thread on a variable while(old_thread-&gt;GetWait()) { internal_sched_yield(); } 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 fiber in sequential mode, no problems with TLS. 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 fiber, because context switching occurs with the help of OS.</p><p>5 Scheduling algorithms</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="5.1">Random Scheduler</head><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 finding an error.</p><p>The random scheduler implementation uses a uniform distribution. The formula of the distribution density function is as follows:</p><formula xml:id="formula_1">f (x) = 1 b−a , x ∈ [a, b] 0, ∈ [a, b]<label>(1)</label></formula><p>[a, b] -distribution segment of the random value. Such a scheduling algorithm can be useful for its speed, low memory consumption and the probability of quickly finding an error without even regardless its shortcomings.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="5.2">Scheduler with different distributions of random values</head><p>Scheduler with different 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 first element. Number generators of random values from 1..n, then the first 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 different).</p><p>Random value generators that were used in the implementation of the planning algorithm with different 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 finding errors, it will be more due to the fact that the first generator of random values corresponds to a uniform distribution as in a random scheduler, and other generators are completely different from it, which will allow us to find new types of errors. Similarly, the locality of finding 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 find different errors fine-tuning of algorithms. But the main advantage of such an algorithm is that it can find 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.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="5.3">Full search scheduler</head><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. 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 flow 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. 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 first 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.</p><p>Table <ref type="table">1</ref>. An array of values describing the iteration Time 0 1 2 3 4 5 6 7 8 9 Tid 0 0 0 0 0 0 0 0 0 0 MaxTid 0 1 1 2 2 2 2 3 2 0</p><p>The most difficult part of the algorithm is to learn to define 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. 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.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="5.4">Scheduler based on full paths with floating window</head><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 floating window" 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 fixed 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 find new mistakes</p><p>The main advantage of this algorithm is that if we choose a small window size, we can get the final algorithm even from a practical point of view. Therefore, the working time of the algorithm is considered finite. This algorithm does not cover all possible ways if we compare it with the previous example, but we can choose an infinitely large window and then it will correspond to the previous algorithm</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="5.5">Brute force based scheduler</head><p>All the above algorithms have a lack of working time. Even a fixed 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 first 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. Table <ref type="table">2</ref>. First iteration Time 0 1 2 3 used 0 1 1 0 variants 0,1 0,1 0,1 0,1 Table <ref type="table">3</ref>. Second iteration Time 0 1 2 3 used 0,1 1,0 1,0 0,1 variants 0,1 0,1 0,1 0,1</p><p>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.</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="6">Test results</head><p>Testing was conducted in several steps:</p><p>1. Using existing Tests Google Thread Sanitizer 2. Find cases for which schedulers can be useful 3. Testing the libcds library Tests provided by Google Thread Sanitizer required further refinement 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: In lines 5, 6 on the variable a there is a data race. Several thousand iterations using the operating system scheduler did not find this problem. All the developed schedulers were tested on this example and each was able to detect the data race on the variable a Let's look at an interesting example:  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</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="7">Related work</head><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 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</p></div><figure xmlns="http://www.tei-c.org/ns/1.0" xml:id="fig_0"><head></head><label></label><figDesc>The second disadvantage is not working with the following example: (); t2.join(); cout &lt;&lt; "Finish" &lt;&lt; endl; }</figDesc></figure>
<figure xmlns="http://www.tei-c.org/ns/1.0" xml:id="fig_3"><head></head><label></label><figDesc>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; }</figDesc></figure>
<figure xmlns="http://www.tei-c.org/ns/1.0" xml:id="fig_4"><head></head><label></label><figDesc>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 different 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:</figDesc></figure>
<figure xmlns="http://www.tei-c.org/ns/1.0" xml:id="fig_5"><head>Fig. 1 .</head><label>1</label><figDesc>Fig. 1. Scheduling comparison</figDesc><graphic coords="11,134.77,314.55,365.40,178.20" type="bitmap" /></figure>
		</body>
		<back>
			<div type="annex">
<div xmlns="http://www.tei-c.org/ns/1.0"><p>parallel scheduling algorithm <ref type="bibr" target="#b7">[8]</ref>, acceleration of developed algorithms, Modeling the order of visibility of variables <ref type="bibr" target="#b8">[9]</ref> [1], development of a scheduler to check the properties of lock free algorithms</p></div>
<div xmlns="http://www.tei-c.org/ns/1.0"><head n="8">Conclusion</head><p>Various platforms and scheduling algorithms were considered in this paper. And as a result, the following tasks were completed:</p><p>1. TSAN has developed three platforms for managing threads 2. Implemented schedulers in TSAN 3. Bugs found and fixed in TSAN 4. Testing of developed tools Currently, there are examples where Google Thread Sanitizer does not find errors using the operating system scheduler, and the developed infrastructure allows to find missed errors. This shows that the goal is achieved, the developed tool helps to find errors in multithreaded code that was previously difficult to detect.</p></div>			</div>
			<div type="references">

				<listBibl>

<biblStruct xml:id="b0">
	<monogr>
		<author>
			<persName><forename type="first">M</forename><surname>Batty</surname></persName>
		</author>
		<author>
			<persName><forename type="first">S</forename><surname>Owens</surname></persName>
		</author>
		<author>
			<persName><forename type="first">S</forename><surname>Sarkar</surname></persName>
		</author>
		<author>
			<persName><forename type="first">P</forename><surname>Sewell</surname></persName>
		</author>
		<author>
			<persName><forename type="first">T</forename><surname>Weber</surname></persName>
		</author>
		<title level="m">Mathematizing C++ Concurrency // POPL</title>
				<imprint>
			<date type="published" when="2011">2011</date>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b1">
	<monogr>
		<title level="m" type="main">CDS C++ library [Electronic Resource</title>
		<author>
			<persName><forename type="first">M</forename><surname>Khizhinsky</surname></persName>
		</author>
		<ptr target="https://github.com/khizmax/libcds" />
		<imprint>
			<date type="published" when="2018-12-04">date 04.12.2018</date>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b2">
	<monogr>
		<title level="m" type="main">Relacy Race Detector [Electronic Resource</title>
		<author>
			<persName><forename type="first">D</forename><surname>Vyukov</surname></persName>
		</author>
		<ptr target="https://github.com/dvyukov/relacy" />
		<imprint>
			<date type="published" when="2018-11-15">date 15.11.2018</date>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b3">
	<monogr>
		<title level="m" type="main">Introduction [Electronic Resource</title>
		<author>
			<persName><forename type="first">D</forename><surname>Vyukov</surname></persName>
		</author>
		<author>
			<persName><surname>Rrd</surname></persName>
		</author>
		<ptr target="http://www.1024cores.net/home/relacy-race-detector/rrd-introduction" />
		<imprint>
			<date type="published" when="2018-11-25">date 25.11.2018</date>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b4">
	<monogr>
		<title level="m" type="main">ELF Handling For Thread-Local Storage</title>
		<author>
			<persName><forename type="first">U</forename><surname>Drepper</surname></persName>
		</author>
		<imprint>
			<date type="published" when="2005">2005</date>
			<publisher>Red Hat Inc</publisher>
			<biblScope unit="page">79</biblScope>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b5">
	<monogr>
		<author>
			<persName><forename type="first">O</forename><forename type="middle">V</forename><surname>Doronin</surname></persName>
		</author>
		<author>
			<persName><forename type="first">E</forename><forename type="middle">L</forename><surname>Kalishenko</surname></persName>
		</author>
		<author>
			<persName><forename type="first">E</forename><forename type="middle">L</forename><surname>Kalishenko</surname></persName>
		</author>
		<ptr target="http://kmu.ifmo.ru/collectionsarticle/7307/analizproblemvRelacyRaceDetectorsposleduyuschimustraneniem.htm" />
		<title level="m">Analiz problem v Relacy Race Detector s posleduyushchim ustraneniem // Sbornik tezisov dokladov kongressa molodyh uchenyh</title>
				<imprint>
			<date type="published" when="2018-11-20">date 20.11.2018</date>
		</imprint>
	</monogr>
	<note>Electronic Resource. Language Russian</note>
</biblStruct>

<biblStruct xml:id="b6">
	<analytic>
		<title level="a" type="main">Google Thread Sanitizer</title>
	</analytic>
	<monogr>
		<title level="m">Electronic Resource</title>
				<imprint/>
	</monogr>
</biblStruct>

<biblStruct xml:id="b7">
	<monogr>
		<title level="m" type="main">Multicore acceleration of priority-based schedulers for concurrency bug detection</title>
		<author>
			<persName><forename type="first">S</forename><surname>Nagarakatte</surname></persName>
		</author>
		<author>
			<persName><forename type="first">S</forename><surname>Burckhardt</surname></persName>
		</author>
		<author>
			<persName><forename type="first">M</forename><forename type="middle">M</forename><surname>Martin</surname></persName>
		</author>
		<author>
			<persName><forename type="first">M</forename><surname>Musuvathi</surname></persName>
		</author>
		<imprint>
			<date type="published" when="2012">2012</date>
			<publisher>ACM</publisher>
		</imprint>
	</monogr>
</biblStruct>

<biblStruct xml:id="b8">
	<monogr>
		<title level="m" type="main">Dynamic Race Detection for C++11</title>
		<author>
			<persName><forename type="first">C</forename><surname>Lidbury</surname></persName>
		</author>
		<author>
			<persName><forename type="first">A</forename><forename type="middle">F</forename><surname>Donaldson</surname></persName>
		</author>
		<imprint>
			<date type="published" when="2016">2016</date>
			<publisher>POPL</publisher>
		</imprint>
	</monogr>
</biblStruct>

				</listBibl>
			</div>
		</back>
	</text>
</TEI>
