1
Vote

Alpaca Test reports Data Race but don't know why

description

I wrote some Alpaca Tests and really like the tool and it helped me a lot in finding bad code.
But with the following lines of code I get a Data Race error but don't know why. Can you please be so kind and give me some insights why this is the case?
BTW: I'm using build 61646 from http://ppcp.codeplex.com
 
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Microsoft.Concurrency.TestTools.UnitTesting;

namespace MOCTestProject
{
public class AlpacaTest
{
    [DataRaceTestMethod]
    public void AddAndRemove()
    {
        ConcurrentDictionary<string, MyData> ccd = new ConcurrentDictionary<string, MyData>();

        Parallel.Invoke(
            () => ccd.TryAdd("k1", new MyData()),

            () =>
            {
                MyData data;
                if (ccd.TryRemove("k1", out data))
                {
                    data.Cleanup();
                }
            }
            );
    }
}

public class MyData
{
    private string data;

    public MyData()
    {
        data = "value";
    }

    public void Cleanup()
    {
        data = null;
    }
}
}

file attachments

comments

mormayo wrote Mar 31, 2011 at 10:43 AM

MatthiasFG,

Have you tried viewing the data race from within the Concurrency Explorer? Right now it takes a little to get used to but works nicely.
1) Select the task that found your data race
2) In the lower left box in the UI Right-click the "R1 Found data race at ..." and select "Repro R1 with Tracing". This will launch a new task to run the schedule where that data race was found, with tracing info included.
3) Right-click the R1 result again and this time select "View Race with Concurrency Explorer". This will jump you to where the data race happened, i.e. where two threads are accessing a memory location where one is a write and the location (variable) isn't protected by a lock or volatile.

wrote Mar 31, 2011 at 10:48 AM

mormayo wrote Mar 31, 2011 at 10:48 AM

Tom,

I thought that memory accesses in a constructor are guaranteed to be executed before returning. i.e. there shouldn't be a way to interleave the two threads because since the .ctor hasn't finished, it couldn't have been added to the dictionary. Therefore, the MyData instance returned from TryRemove would refer to an instance that has had it's .ctor fully executed.

Can you explain if this is a bug w/CHESS or if my assumptions above are incorrect.

Thanks,
JoeM

MatthiasFG wrote Mar 31, 2011 at 4:57 PM

JoeM,

yes, i already tried and used the Concurrency Explorer and i'm familiar with it.
But as you kindly added, I got the same picture as you already added. Thanks!

BTW: I have some more inconvenience with Alpaca when using Lambdas instead of "regular" foreach loops. If you care I can post them too.

-Matthias

mormayo wrote Mar 31, 2011 at 5:37 PM

Matthias,

Yes, we love all the feedback we can get. Just post as different threads. Your sample code was great since it was complete. Thanks!

MatthiasFG wrote Apr 11, 2011 at 6:51 AM

push
Nothing new?

mormayo wrote May 2, 2011 at 11:13 PM

Matthias,

I've also tried modifying your example to remove one possible complication; I changed the following line(s):
() => ccd.TryAdd("k1", new MyData()),
to:
() => {
var d = new MyData();
ccd.TryAdd("k1", d);
},

This has the same data race as your code, but for me, clarifies that the issue isn't with using the TryAdd method. What the data race is suggesting is that field writes in ctors are not thread safe. I may be wrong, but I do believe that this shouldn't be the case.

I can see a scenario where this might be a useful assumption to exploit:
Have one thread instantiate an object via only a call to a ctor (e.g. producer) and add to some thread-safe queue. Then another thread (e.g. consumer) could retrieve this object from the queue to process it. If this consuming thread doesn't pass the object on, then it makes sense to want these data objects to not have to have thread-safe constructs (for performance and ease of use reasons).

Of course, if another thread got a hold of this data object, then thread-saftey constructs would need to be used.

Again, I'll refer an explanation of this to Tom or Sebastian, who I know are quite busy with other projects.

MatthiasFG wrote May 3, 2011 at 6:20 AM

Joe,

thanks for you reply.
What the data race is suggesting is that field writes in ctors are not thread safe. I may be wrong, but I do believe that this shouldn't be the case.
As like I do. Why should a ctor not be threadsafe? I really can't think of situations where this might happen (even not you producer/consumer sample).
Have you had a chance to have a look on my other reported issues regarding the lambdas?

BTW: currently we face another problem with using a combination of lock() and ReadOnlyCollection<T>. I'll try to break it down and will report it as a new issue.

Hope we will get some more insights (and fixes) from Tom or Sebastian.

-Matthias

wrote May 3, 2011 at 8:57 PM

Associated with changeset 58005.

MatthiasFG wrote May 4, 2011 at 2:09 PM

Hi Joe!

I downloaded 58009 and build Alpaca and all the other projects and run it on my sample code.
But I still get the DataRace reports.
Did I made something wrong?

-Matthias

mormayo wrote May 4, 2011 at 7:02 PM

I only checked in the code that reproduces the issues. Nothing has been fixed by them.

MatthiasFG wrote May 4, 2011 at 9:10 PM

I was just wondering why there was the "Associated with changeset 58005" statement.

-Matthias

wrote Feb 14, 2013 at 7:24 PM