Thread question

Ok, when you have like 2 threads, 1 writes into a variable and one reads from the same variable, when you are not synchronizing, what can happen? I know that if the variable is larger than 1 byte, that the reading thread can read a partly updated value because the writer thread was updating it on the same time. But can things like access violation happen in this scenario? And what other things can happen?

Thanks.
IIRC, on x86, memory accesses (both in and out) are atomic for aligned data (as long as the data fits entirely in the cache line).

Segmentation faults are strictly memory protection issues. As long as the program doesn't go off using memory that doesn't belong to it, the system won't crash it (at least not because of a segmentation fault). It can do whatever it wants with the memory that does belong to it. Race conditions can't be detected, anyway.
Last edited on
Well, ok, thanks, but then I got another question, because I can't seem to figure it out and first wanted to know if that could be the problem.

I have a class, which causes access violation exceptions when I use the "AddValue" function of it, which is used on another thread than the main thread. This is the function:
1
2
3
4
5
6
7
8
9
10
11
12
void AddValue(const dataType& value)
{
	if (size == cap)
	{
		for (uint32 i = 0, j = 1; j < cap; i++, j++)
			buffer[i] = buffer[j];
	}
	else
		size++;

	buffer[size - 1] = value;
}
The size of the buffer is 60 in this scenario and cap is 60 too.
Now when I comment thing out like this:
1
2
3
4
5
6
7
8
9
10
11
12
void AddValue(const dataType& value)
{
	/*if (size == cap)
	{
		for (uint32 i = 0, j = 1; j < cap; i++, j++)
			buffer[i] = buffer[j];
	}
	else
		size++;*/

	buffer[size - 1] = value;
}
Nothing happens. But when I comment out things like this:
1
2
3
4
5
6
7
8
9
10
11
12
void AddValue(const dataType& value)
{
	if (size == cap)
	{
		/*for (uint32 i = 0, j = 1; j < cap; i++, j++)
			buffer[i] = buffer[j];*/
	}
	else
		size++;

	buffer[size - 1] = value;
}
I do get the exceptions. I rly can't think of anything that may caused the problem.

I would really appreciate any help ^^.
You have a race condition, there. When there's one thread reading and one thread writing, it's one thing, but that function first reads, then writes to size, then reads it again. An example execution:
1. Thread 0 reads and compares size.
2. Thread 1 reads and compares size.
3. Thread 1 increments size by first reading it again and then writing it back.
4. Thread 0 increments size by first reading it again and then writing it back.
5. size was incremented one time too many.
An even worse case:
1. Thread 0 reads half 0 of size.
2. Thread 1 reads half 0 of size.
3. Thread 0 reads half 1 of size.
4. Thread 1 reads half 1 of size.
(Comparison and increment skipped.)
5. Thread 0 writes half 0 of size.
6. Thread 1 writes half 0 of size.
7. Thread 1 writes half 1 of size.
8. Thread 0 writes half 1 of size.
9. size contains garbage.

Lock the function and any other place where the variable is used asynchronously.
Last edited on
Well, there is actually one thread using that function, and the other thread is using these 2 functions to read out (it's a template class, where the typename is dataType):
1
2
uint32 GetSize() { return size; }
dataType GetValue(const uint32& index) { return buffer[index]; }

I thought that there couldn't be a race condition. Do you still think so?
Last edited on
size doesn't seem to get larger than cap, so it doesn't access outside the buffer right?
You have a race condition. The behavior is undefined.
Ok, I have commented out any lines that uses this class (called Buffer btw). Now I have only this thread left that is doing this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void SensorPanelWindow::sensorWorker(SensorBuffer* sensorBuffer, MeasuringDevice* device, bool* stopSign)
{
	WaitTime wt(100);
	mutex::scoped_lock lock(sensorBuffer->mutex, boost::defer_lock);

	while (!(*stopSign))
	{
		lock.lock();
		sensorBuffer->buffer.AddValue(device->GetValue());
		lock.unlock();

		wt.WaitForNextInterval(); //Wait for the next 100 milisecond interval
	}
}

I have checked with breakpoints, that there is only one thread doing this.
Then how is it possible that a race condition occurs? (Maybe I'm getting the concept of a race condition wrong.)
Last edited on
Ok, I found the problem. I didn't know the destructor was called on Buffer objects which doesn't get initialized, which ofcourse trigger the default destructor. It kinda stupid because it needs to call the destructor ofcourse. Anyway, the destructor deletes the internal buffer pointer, and because the uninitialized Buffers used the default contructors which don't create a buffer, the buffer wasn't created, which leads to unexpected behavior.

I also not get why acces violation occurred when I clicked on the menubar, it was created right after Buffer.

Thanks anyway for the effort. ^^
in answer to you original question,
here's an excerpt of a test i did, 50 threads incrementing a variable a total of 5 million times...

1
2
3
4
5
6
    
while(t--) {
        A.lock();
        ::count++;
        A.unlock();
    }


with the lock
1
2
$ ./unlocked_thread_increment | commify
count = 5,000,000


and commented out:
1
2
3
4
5
6
$ ./unlocked_thread_increment | commify
count = 2,108,284
$ ./unlocked_thread_increment | commify
count = 1,198,639
$ ./unlocked_thread_increment | commify
count = 2,473,065

Topic archived. No new replies allowed.