Shared memory across threads

C

Curious

I'm working on a multi-threading project and I've got an issue about
shared memory used by multiple threads at the same time.

I have two separate threads that have different callback methods.
Thread one is to create an ArrayList called "mHistoricalList" and add
things to it. Thread two is looping through the same list at the same
time. While thread one is adding things to the list, thread two is
unable to loop the list. So the program crashed.

So I was thinking of using "lock". But it doesn't work - It gives me a
runtime unknown error. My code is below (in the callback methond on
thread one):

void CreateHistoricalList (string ticker, double openPrice, double
volume)
{
lock (mHistoricalList)
{
SymbolPriceVolume spv = new SymbolPriceVolume(ticker);
PriceVolume pv = new PriceVolume(openPrice, volume);
spv.PriceVolumeArray.Add(pv);
mHistoricalList.Add(spv);
}
}

Is there anything wrong with the way I use the "lock"? Could anyone
advise me on how I can get this fixed? Thanks!
 
C

Curious

Hi Frederic,

I tried with the wrapper of ArrayList. It crashed again. I got the
same exception:

"Unhandled exception at 0x7c812a5b in TSF_Server_1.exe: 0xC0020001:
The string binding is invalid."

FYI, I changed the code as below:

ArrayList myThreadSafeHistoricalList =
ArrayList.Synchronized(mHistoricalList);

SymbolPriceVolume spv = new SymbolPriceVolume(ticker);

PriceVolume pv = new PriceVolume(openPrice, volume);
spv.PriceVolumeArray.Add(pv);
mHistoricalList.Add(spv);


Shall I replace "mHistoricalList" everywhere with
"myThreadSafeHistoricalList"? Do I still need to use "lock"?
 
C

Curious

Hi Frédéric,

According to your suggestion, I changed my callback on thread one as
below:

void CreateHistoricalList (string ticker, double openPrice, double
volume)
{
ArrayList myThreadSafeHistoricalList =
ArrayList.Synchronized(mHistoricalList);
SymbolPriceVolume spv = new SymbolPriceVolume(ticker);
PriceVolume pv = new PriceVolume(openPrice, volume);
spv.PriceVolumeArray.Add(pv);
myThreadSafeHistoricalList.Add(spv);

}

However, it crashed again for the same unhandled exception. Did I do
anything wrong? Shall I replace "mHistoricalList" with
"myThreadSafeHistoricalList" in the callback on thread two as well
(and everywhere else)?
 
A

Adam Benson

Hi,

Leave thread one as it is.

Thread two should look something like this :

lock (mHistoricalList)
{
foreach (SymbolPriceVolume spv in mHistoricalList)
{
// Do stuff here
}
}

Are you locking your list for the whole time you iterate over it?

If one thread is enumerating a list and another thread alters the list
you're going to have one unhappy computer on your hands.

On another note I'd encourage you to take a step back and ask why you need 2
threads accessing a list in this way. Enumerating a list can be a long time
to lock the whole thing down.

- Adam.
==============
 
F

Frédéric Queudret

Hi,

I tried to reproduce your problem and finally it worked fine for me using a
lock on the SyncRoot property of the ArrayList instance.
The code I used to reproduce is the following one.
Let me know if it solvees your problem:
public class Class1
{
private ArrayList _items;
private Thread _t1;
private Thread _t2;

public Class1()
{
_items = new ArrayList();
}

public void Execute()
{
_t2 = new Thread(new ThreadStart(ShowItems));
_t1 = new Thread(new ThreadStart(AddItems));
_t1.Start();
_t2.Start();
}

public void ShowItems()
{
while (true)
{
//ArrayList synchItems = ArrayList.Synchronized(_items); <-
doesn't work
lock (_items.SyncRoot)
{
foreach (object item in _items)
{
Console.WriteLine((string)item);

}
}

}
}
public void AddItems()
{
int cpt = 0;
while (true)
{
//ArrayList synchItems = ArrayList.Synchronized(_items); <-
does not work
lock (_items.SyncRoot)
{
_items.Add("CPT" + cpt.ToString());
}
cpt++;

}
}
}

Frédéric

Hi Frédéric,

According to your suggestion, I changed my callback on thread one as
below:

void CreateHistoricalList (string ticker, double openPrice, double
volume)
{
ArrayList myThreadSafeHistoricalList =
ArrayList.Synchronized(mHistoricalList);
SymbolPriceVolume spv = new SymbolPriceVolume(ticker);
PriceVolume pv = new PriceVolume(openPrice, volume);
spv.PriceVolumeArray.Add(pv);
myThreadSafeHistoricalList.Add(spv);

}

However, it crashed again for the same unhandled exception. Did I do
anything wrong? Shall I replace "mHistoricalList" with
"myThreadSafeHistoricalList" in the callback on thread two as well
(and everywhere else)?
 
C

Curious

The callback method is huge and long on thread two. If I use "lock" in
it, it'll block other thread for a long time.

Question: If I use "lock", shall I use it in both the callback methods
on both threads?
 
C

Curious

Hi Frédéric,

Thanks for showing me working code.

However, your sample code doesn't work for my program, because the
ArrayList is altered in both the callback method on thread one, and
the callback method on thread two.

Thread one is adding new objects to the ArrayList, while thread two is
looping through the list and altering some objects already on the
list.

In your case, thread one is adding new objects but thread two is
looping the list without changing the list. In other words, thread one
is "write" operation while thread two is "read" operation.

In my case, both threads are "write" operations.
 
F

Frédéric Queudret

Ok, but it does work too on my sample if you alter the ArrayList on the
second thread.
The sample code is:

public void ShowAndAlterItems()
{
while (true)
{
lock (_items.SyncRoot)
{
_items[_items.Count - 1] = _items[_items.Count - 1] + "
altered from t2";
foreach (object item in _items)
{
Console.WriteLine((string)item);
}
// add a new item
_items.Add("Hello From Thread 2");
}

}
}
public void AddItems()
{
int cpt = 0;
while (true)
{
lock (_items.SyncRoot)
{
_items.Add("CPT" + cpt.ToString());
}
cpt++;
}
}

Do you have any code that show the issue here?
Frédéric

Hi Frédéric,

Thanks for showing me working code.

However, your sample code doesn't work for my program, because the
ArrayList is altered in both the callback method on thread one, and
the callback method on thread two.

Thread one is adding new objects to the ArrayList, while thread two is
looping through the list and altering some objects already on the
list.

In your case, thread one is adding new objects but thread two is
looping the list without changing the list. In other words, thread one
is "write" operation while thread two is "read" operation.

In my case, both threads are "write" operations.
 
A

Adam Benson

Question: If I use "lock", shall I use it in both the callback methods
on both threads?
Yes. Its the only safe way to alter or read a collection from more than 1
thread.

Why does your worker thread have to enumerate the whole list? Is it looking
for something in particular to act on? Instead of searching through the
whole list every time, would an event work better? You may find if you take
a step back and look at the problem again you don't have to enumerate the
whole collection repeatedly. It's difficult to be more specific without
knowing the details, of course.

=======
- Adam.
 
A

Adam Benson

I meant alter and read - not alter or read.
You could have as many threads as you like reading the container, but as
soone as 1 thread alters it they *all* have to lock.

AB
========
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top