473,387 Members | 1,864 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

strange threading context

This is my problem:

I have two classes A and B:

class A
{
void methodA();
}

class B
{

void methodB();

struct S
{
int Size;
};

S & getMyStruct();

S MyStruct;

}
methodA and methodB get executed in two different threads concurrently.
They both access the variable Size in the structure MyStruct of type S.
methodA gets a reference to this struct by calling getMyStruct which returns
a reference
to it.
Here comes the strange part:
if methodB alters the value of Size from 0 to 1, this change doesn't get
reflected in methodA - methodA
still reads a 0. The access to the struct MyStruct is sychronized by a
mutex.

Whats going on here? Why are the changes of Size by thread executing methodB
not visible to the thread executing methodA.
I thought that struct myStruct lies in the context of both threads/methods.

Regards

A.Gallus

Aug 16 '08 #1
5 1541
A.Gallus wrote:
This is my problem:

I have two classes A and B:

class A
{
void methodA();
}

class B
{

void methodB();

struct S
{
int Size;
};

S & getMyStruct();

S MyStruct;

}
methodA and methodB get executed in two different threads concurrently.
They both access the variable Size in the structure MyStruct of type S.
methodA gets a reference to this struct by calling getMyStruct which
returns a reference
to it.
Here comes the strange part:
if methodB alters the value of Size from 0 to 1, this change doesn't get
reflected in methodA - methodA
still reads a 0. The access to the struct MyStruct is sychronized by a
mutex.
Show the code. If you don't have an appropriate memory barrier each
thread/core may have the local copy in a register.

--
Ian Collins.
Aug 16 '08 #2
"A.Gallus" <uh**@rz.uni-karlsruhe.dewrote in message
news:g8**********@news2.rz.uni-karlsruhe.de...
This is my problem:

I have two classes A and B:

class A
{
void methodA();
}

class B
{

void methodB();

struct S
{
int Size;
};

S & getMyStruct();

S MyStruct;

}
methodA and methodB get executed in two different threads concurrently.
They both access the variable Size in the structure MyStruct of type S.
methodA gets a reference to this struct by calling getMyStruct which
returns a reference
to it.
Here comes the strange part:
if methodB alters the value of Size from 0 to 1, this change doesn't get
reflected in methodA - methodA
still reads a 0. The access to the struct MyStruct is sychronized by a
mutex.
Well, let me try to read your mind and see if I can make a better model in
the form of fully compliable code:

code listing 1 with a race-condition!
__________________________________________________ ____________________
#include <cstdio>
#include <pthread.h>
class mutex_guard {
pthread_mutex_t* const m_mutex;

public:
mutex_guard(pthread_mutex_t* const mutex)
: m_mutex(mutex) {
pthread_mutex_lock(m_mutex);
}

~mutex_guard() {
pthread_mutex_unlock(m_mutex);
}
};
class A {
public:
void methodA();
};

class B {
friend class A;

struct S {
int Size;
S() : Size() {}
};

S MyStruct;

S& getMyStruct() {
return MyStruct;
}

static pthread_mutex_t g_mutex;

public:
void methodB();
};
pthread_mutex_t B::g_mutex = PTHREAD_MUTEX_INITIALIZER;
static B g_global_instance_of_B;
static A g_global_instance_of_A;
void A::methodA() {
mutex_guard lock(&B::g_mutex);
std::printf("A::methodA() - B::MyStruct::Size == %d\n",
g_global_instance_of_B.getMyStruct().Size);
}
void B::methodB() {
mutex_guard lock(&B::g_mutex);
MyStruct.Size = 1;
std::printf("B::methodB() - B::MyStruct::Size == %d\n",
g_global_instance_of_B.getMyStruct().Size);
}
extern "C" void* thread_1(void*) {
g_global_instance_of_A.methodA();
return NULL;
}
extern "C" void* thread_2(void*) {
g_global_instance_of_B.methodB();
return NULL;
}
int main() {
pthread_t tid[2];
pthread_create(&tid[0], NULL, thread_1, NULL);
pthread_create(&tid[1], NULL, thread_2, NULL);
for (int i = 0; i < 2; ++i) {
pthread_join(tid[i], NULL);
}
return 0;
}

__________________________________________________ ____________________
Okay, this program can run 3 ways... The first is that thread_1 runs first
and therefore misses the update. Second, thread_2 runs first and the update
is observed when thread_1 runs. The third is that they run together and race
through in which anything can happen. For instance, if thread_1 hits the
mutex first, then the update will not be observed.

If you want to ensure that thread_1 will ALWAYS see the mutation generated
by thread_2, well, you need someway to make sure that thread_2 runs first. A
simple and niave soultion is to use a simple semaphore. Think of this:
code listing 2 without a race-condition!
__________________________________________________ ____________________
#include <cstdio>
#include <pthread.h>
#include <semaphore.h>
class mutex_guard {
pthread_mutex_t* const m_mutex;

public:
mutex_guard(pthread_mutex_t* const mutex)
: m_mutex(mutex) {
pthread_mutex_lock(m_mutex);
}

~mutex_guard() {
pthread_mutex_unlock(m_mutex);
}
};
class A {
public:
void methodA();
};

class B {
friend class A;

struct S {
int Size;
S() : Size() {}
};

S MyStruct;

S& getMyStruct() {
return MyStruct;
}

static pthread_mutex_t g_mutex;

public:
void methodB();
};
pthread_mutex_t B::g_mutex = PTHREAD_MUTEX_INITIALIZER;
static B g_global_instance_of_B;
static A g_global_instance_of_A;
void A::methodA() {
mutex_guard lock(&B::g_mutex);
std::printf("A::methodA() - B::MyStruct::Size == %d\n",
g_global_instance_of_B.getMyStruct().Size);
}
void B::methodB() {
mutex_guard lock(&B::g_mutex);
MyStruct.Size = 1;
std::printf("B::methodB() - B::MyStruct::Size == %d\n",
g_global_instance_of_B.getMyStruct().Size);
}
extern "C" void* thread_1(void* state) {
sem_t* const sem = (sem_t*)state;
sem_wait(sem);
g_global_instance_of_A.methodA();
return NULL;
}
extern "C" void* thread_2(void* state) {
sem_t* const sem = (sem_t*)state;
g_global_instance_of_B.methodB();
sem_post(sem);
return NULL;
}
int main() {
pthread_t tid[2];
sem_t sem;
sem_init(&sem, 0, 0);
pthread_create(&tid[0], NULL, thread_1, &sem);
pthread_create(&tid[1], NULL, thread_2, &sem);
for (int i = 0; i < 2; ++i) {
pthread_join(tid[i], NULL);
}
sem_destroy(&sem);
return 0;
}

__________________________________________________ ____________________
Now, thread_1 will always see the mutation made by thread_2. Period, end of
story. thread_1 will ALWAYS output:
A::methodA() - B::MyStruct::Size == 1

Whats going on here? Why are the changes of Size by thread executing
methodB not visible to the thread executing methodA.
I thought that struct myStruct lies in the context of both
threads/methods.
Perhaps the thread in which methodA gets invoked happens to execute first,
thus it has no chance to observe the mutation made by the thread which
invokes methodB.

Aug 17 '08 #3
When I create MyStruct on the heap (with new) instead writing it as a
reference class member everything works fine:

S * getMyStruct();

S * MyStruct;

It seems to me that both classes are working on another copy of MyStruct
when I don't use
new(). I doubt that I have a race condition, unfortunately the code is way
to long to post it here.

Thx guys!

Regards

A.Gallus
Aug 17 '08 #4
A.Gallus wrote:
When I create MyStruct on the heap (with new) instead writing it as a
reference class member everything works fine:

S * getMyStruct();

S * MyStruct;

It seems to me that both classes are working on another copy of MyStruct
when I don't use
new(). I doubt that I have a race condition, unfortunately the code is
way to long to post it here.
Then post a simplified example. You'll probably solve the problem
writing it.

--
Ian Collins.
Aug 17 '08 #5
A.Gallus schrieb:
When I create MyStruct on the heap (with new) instead writing it as a
reference class member everything works fine:
You had it as reference class member instead of as value member?
S * getMyStruct();

S * MyStruct;

It seems to me that both classes are working on another copy of MyStruct
when I don't use
new(). I doubt that I have a race condition, unfortunately the code is
way to long to post it here.
You could check that by printing the address of the member and the
address of the containing class in both threads. If the addresses are
not equal, you are working with two distinct copies.

--
Thomas
Aug 17 '08 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Joe Wong | last post by:
Hi, Is there any way to increase/decrease a thread priority in Python? Best regards, -- Wong
4
by: MJB | last post by:
I never get the above exception in Windows 2k. It only happens in Windows XP, which is the first oddity. My application is multi-threaded and I use the webbrowser control and media player. The...
4
by: Oz | last post by:
This is long. Bear with me, as I will really go through all the convoluted stuff that shows there is a problem with streams (at least when used to redirect stdout). The basic idea is that my...
0
by: sqcliu | last post by:
I encounter a strange problem using platform invoke using C#. The senario is this: I have a dll which uses a 3rd party static link library (lib). Inside the lib, there are some C structures...
4
by: hazz | last post by:
If I successfully run a VS.NET app which includes the following; ************************** APP 1 **************************** m_iIdnt = new...
5
by: Andrew Lippitt | last post by:
What gaurantees are there in the way of which thread the events are called from. I've seen: Thread A Begin Thread B Begin Thread A End Thread A End That seems to indicate that Begin and End...
5
by: Carl J. Van Arsdall | last post by:
Hi everyone, I'm trying to use the threading module with python 2.2 and I have some questions regarding python's threading. 1. Who schedules which threads run and when? Is this something left...
2
by: Spam Catcher | last post by:
Anyone know what this error means? The Undo operation encountered a context that is different from what was applied in the corresponding Set operation. The possible cause is that a context was...
0
by: LoneTiger | last post by:
Hi everyone, I've got a smaller problem which I can't get around of. I've seen some quite usefull answers around and was hoing someone might be able to help. What I'm working on is a...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.