Question

I'm trying to create a method which when passed a datatable reference with pingable host names, tries to ping each of the hosts and then change the value of corresponding column and row depending on ping success.

However i cannot use references in Parallel.ForEach method. Is there any way i could make this work?

Here's my code:

public void checkON(ref DataTable PCS)
    {

        Parallel.ForEach(PCS.AsEnumerable(), pc =>
            {
                string loopIp = pc["Name"].ToString();
                if (PingIP(loopIp))
                {
                    DataRow[] currentpc = PCS.Select("Name = '{0}'", loopIp);
                    currentpc[0]["Online"] = "ON";
                }
                else
                {
                    DataRow[] currentpc = PCS.Select("Name = '{0}'", loopIp);
                    currentpc[0]["Online"] = "OFF";
                }
            }
        );}
Was it helpful?

Solution

Unless code explicitly says that it is thread-safe, you should assume it is not - and therefore access must be synchronized. The ref in your code serves no purpose. Each pc is a DataRow, so you can access that directly:

string loopIp;
lock(someLockObject) {
    loopIp = (string)pc["Name"];
}
string online = PingIP(loopIp) ? "ON" : "OFF";
lock(someLockObject) {
    pc["Online"] = online;
}

where someLockObject is shared between all of the callers, because you can't make assumptions about the threading model:

object someLockObject = new object();
Parallel.ForEach(PCS.AsEnumerable(), pc =>
        { ... });

In particular, you can't just lock the row because DataTable doesn't store data in rows (it stores it in columns; no, really).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top