Simplest Mutex ever. Does this example work? Is it thread-safe?
I would like to ask about the simplest Mutex approach ever for multi-threading. Is the following code thread-safe (quick-n-dirty)?
class myclass
{
bool locked;
vector<double> vals;
myclass();
void add(double val);
};
void myclass::add(double val)
{
if(!locked)
{
this->locked = 1;
this->vals.push_back(val);
this->locked = 0;
}
else
{
this->add(val);
}
}
int main()
{
myclass cls;
//start parallelism
cls.add(static_cast<double>(rand()));
}
Does this work? Is it thread-safe? I'm just trying to understand how the simplest mutex can be written.
If you have any advice about my example, would be nice.
Thank you.
Thanks for saying that it doesn't work. Can you please suggest a fix which is compiler independent?
c++ multithreading parallel-processing global-variables mutex
add a comment |
I would like to ask about the simplest Mutex approach ever for multi-threading. Is the following code thread-safe (quick-n-dirty)?
class myclass
{
bool locked;
vector<double> vals;
myclass();
void add(double val);
};
void myclass::add(double val)
{
if(!locked)
{
this->locked = 1;
this->vals.push_back(val);
this->locked = 0;
}
else
{
this->add(val);
}
}
int main()
{
myclass cls;
//start parallelism
cls.add(static_cast<double>(rand()));
}
Does this work? Is it thread-safe? I'm just trying to understand how the simplest mutex can be written.
If you have any advice about my example, would be nice.
Thank you.
Thanks for saying that it doesn't work. Can you please suggest a fix which is compiler independent?
c++ multithreading parallel-processing global-variables mutex
5
Making a correct mutex mechanism is a complex business. I would use something already out there.
– andre
Feb 11 '13 at 18:57
Generally, synchronization primitives such as mutexes require some atomicity (often at the CPU instruction level). Here's an interesting link I found: lists.canonical.org/pipermail/kragen-tol/1999-August/…
– Tom
Feb 11 '13 at 19:06
The simplest mutex (or synchronization construct in general) is the one you don't need ;-)
– user395760
Feb 11 '13 at 19:16
add a comment |
I would like to ask about the simplest Mutex approach ever for multi-threading. Is the following code thread-safe (quick-n-dirty)?
class myclass
{
bool locked;
vector<double> vals;
myclass();
void add(double val);
};
void myclass::add(double val)
{
if(!locked)
{
this->locked = 1;
this->vals.push_back(val);
this->locked = 0;
}
else
{
this->add(val);
}
}
int main()
{
myclass cls;
//start parallelism
cls.add(static_cast<double>(rand()));
}
Does this work? Is it thread-safe? I'm just trying to understand how the simplest mutex can be written.
If you have any advice about my example, would be nice.
Thank you.
Thanks for saying that it doesn't work. Can you please suggest a fix which is compiler independent?
c++ multithreading parallel-processing global-variables mutex
I would like to ask about the simplest Mutex approach ever for multi-threading. Is the following code thread-safe (quick-n-dirty)?
class myclass
{
bool locked;
vector<double> vals;
myclass();
void add(double val);
};
void myclass::add(double val)
{
if(!locked)
{
this->locked = 1;
this->vals.push_back(val);
this->locked = 0;
}
else
{
this->add(val);
}
}
int main()
{
myclass cls;
//start parallelism
cls.add(static_cast<double>(rand()));
}
Does this work? Is it thread-safe? I'm just trying to understand how the simplest mutex can be written.
If you have any advice about my example, would be nice.
Thank you.
Thanks for saying that it doesn't work. Can you please suggest a fix which is compiler independent?
c++ multithreading parallel-processing global-variables mutex
c++ multithreading parallel-processing global-variables mutex
edited Feb 11 '13 at 19:02
The Quantum Physicist
asked Feb 11 '13 at 18:55
The Quantum PhysicistThe Quantum Physicist
12.1k748103
12.1k748103
5
Making a correct mutex mechanism is a complex business. I would use something already out there.
– andre
Feb 11 '13 at 18:57
Generally, synchronization primitives such as mutexes require some atomicity (often at the CPU instruction level). Here's an interesting link I found: lists.canonical.org/pipermail/kragen-tol/1999-August/…
– Tom
Feb 11 '13 at 19:06
The simplest mutex (or synchronization construct in general) is the one you don't need ;-)
– user395760
Feb 11 '13 at 19:16
add a comment |
5
Making a correct mutex mechanism is a complex business. I would use something already out there.
– andre
Feb 11 '13 at 18:57
Generally, synchronization primitives such as mutexes require some atomicity (often at the CPU instruction level). Here's an interesting link I found: lists.canonical.org/pipermail/kragen-tol/1999-August/…
– Tom
Feb 11 '13 at 19:06
The simplest mutex (or synchronization construct in general) is the one you don't need ;-)
– user395760
Feb 11 '13 at 19:16
5
5
Making a correct mutex mechanism is a complex business. I would use something already out there.
– andre
Feb 11 '13 at 18:57
Making a correct mutex mechanism is a complex business. I would use something already out there.
– andre
Feb 11 '13 at 18:57
Generally, synchronization primitives such as mutexes require some atomicity (often at the CPU instruction level). Here's an interesting link I found: lists.canonical.org/pipermail/kragen-tol/1999-August/…
– Tom
Feb 11 '13 at 19:06
Generally, synchronization primitives such as mutexes require some atomicity (often at the CPU instruction level). Here's an interesting link I found: lists.canonical.org/pipermail/kragen-tol/1999-August/…
– Tom
Feb 11 '13 at 19:06
The simplest mutex (or synchronization construct in general) is the one you don't need ;-)
– user395760
Feb 11 '13 at 19:16
The simplest mutex (or synchronization construct in general) is the one you don't need ;-)
– user395760
Feb 11 '13 at 19:16
add a comment |
7 Answers
7
active
oldest
votes
Is it thread-safe?
Certainly not. If a thread is preempted between checking and setting the lock, then a second thread could acquire that lock; if control then returns to the first thread, then both will acquire it. (And of course, on a modern processor, two or more cores could be executing the same instructions simultaneously for even more hilarity.)
At the very least, you need an atomic test-and-set operation to implement a lock like this. The C++11 library provides such a thing:
std::atomic_flag locked;
if (!locked.test_and_set()) {
vals.push_back(val);
locked.clear();
} else {
// I don't know exactly what to do here;
// but recursively calling add() is a very bad idea.
}
or better yet:
std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
vals.push_back(val);
If you have an older implementation, then you'll have to rely on whatever extensions/libraries are available to you, as there was nothing helpful in the language or standard library back then.
hmmmmm. Thanks for the answers. I'm using VS2010 and g++, where the first one doesn't support mutex. Any other compiler independent idea?
– The Quantum Physicist
Feb 11 '13 at 19:42
1
@SamerAfach: The Boost.Thread and just::thread libraries have portable and (more or less) direct replacements for the C++11 mutex. Failing that there's the Windows API (critical sections, or whatever they call it); obviously that's not compiler-independent, so you'll need some carefully placed#define
s to select which to use.
– Mike Seymour
Feb 11 '13 at 19:48
@MikeSymour if I use the boost Mutex for example (or any other Mutex), will that make the code thread-safe for other parallelization libraries, like OpenMPI and OpemMP? or does Mutex work exclusively for the parallelism of the library from which the Mutex is taken?
– The Quantum Physicist
Feb 12 '13 at 7:46
1
@SamerAfach: I don't quite understand the question, but I guess the answer is yes. Using a mutex correctly will serialise all sections of code that run with that mutex locked, making that code thread-safe, regardless of whatever parallelisation libraries you're using.
– Mike Seymour
Feb 14 '13 at 10:58
"regardless of whatever parallelisation libraries you're using". That answers my question. Thanks :)
– The Quantum Physicist
Feb 14 '13 at 11:03
add a comment |
No, this is not thread safe. There's a race between
if(!locked)
and
this->locked = 1;
If there is a context switch between these two statements, your lock mechanism falls apart. You need an atomic test and set
instruction, or simply use an existing mutex
.
add a comment |
This code doesn't provide an atomic modification of vals
vector. Consider the following scenario:
//<<< Suppose it's 0
if(!locked)
{ //<<< Thread 0 passes the check
//<<< Context Switch - and Thread 1 is also there because locked is 0
this->locked = 1;
//<<< Now it's possible for one thread to be scheduled when another one is in
//<<< the middle of modification of the vector
this->vals.push_back(val);
this->locked = 0;
}
add a comment |
Does this work? Is it thread-safe?
No. It will fail at times.
Your mutex will only work if other threads never do anything between the execution of these two lines:
if(!locked)
{
this->locked = 1;
...and you have not ensured that.
To learn about the how of mutex writing, see this SO post.
add a comment |
No, that is not thread safe.
Consider two threads running myclass::add
at more-or-less the same time. Also, imagine that the value of .locked
is false
.
The first thread executes up to and including this line:
if(!locked)
{
Now imagine that the system switches context to the second thread. It also executes up to the same line.
Now we have two different threads, both believing that they have exclusive access, and both inside the !locked
condition of the if.
They will both call vals.push_back()
at more-or-less the same time.
Boom.
add a comment |
Others have already shown how your mutex can fail, so I won't rehash their points. I will only add one thing: The simplest mutex implementation is a lot more complicated than your code.
If you're interested in the nitty gritty (or even if you are not - this is stuff every software developer should know) you should look at Leslie Lamport's Bakery Algorithm and go from there.
add a comment |
You cannot implement it in C++. You have to use LOCK CMPXCHG. Here is my answer from here:
; BL is the mutex id
; shared_val, a memory address
CMP [shared_val],BL ; Perhaps it is locked to us anyway
JZ .OutLoop2
.Loop1:
CMP [shared_val],0xFF ; Free
JZ .OutLoop1 ; Yes
pause ; equal to rep nop.
JMP .Loop1 ; Else, retry
.OutLoop1:
; Lock is free, grab it
MOV AL,0xFF
LOCK CMPXCHG [shared_val],BL
JNZ .Loop1 ; Write failed
.OutLoop2: ; Lock Acquired
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f14818915%2fsimplest-mutex-ever-does-this-example-work-is-it-thread-safe%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
7 Answers
7
active
oldest
votes
7 Answers
7
active
oldest
votes
active
oldest
votes
active
oldest
votes
Is it thread-safe?
Certainly not. If a thread is preempted between checking and setting the lock, then a second thread could acquire that lock; if control then returns to the first thread, then both will acquire it. (And of course, on a modern processor, two or more cores could be executing the same instructions simultaneously for even more hilarity.)
At the very least, you need an atomic test-and-set operation to implement a lock like this. The C++11 library provides such a thing:
std::atomic_flag locked;
if (!locked.test_and_set()) {
vals.push_back(val);
locked.clear();
} else {
// I don't know exactly what to do here;
// but recursively calling add() is a very bad idea.
}
or better yet:
std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
vals.push_back(val);
If you have an older implementation, then you'll have to rely on whatever extensions/libraries are available to you, as there was nothing helpful in the language or standard library back then.
hmmmmm. Thanks for the answers. I'm using VS2010 and g++, where the first one doesn't support mutex. Any other compiler independent idea?
– The Quantum Physicist
Feb 11 '13 at 19:42
1
@SamerAfach: The Boost.Thread and just::thread libraries have portable and (more or less) direct replacements for the C++11 mutex. Failing that there's the Windows API (critical sections, or whatever they call it); obviously that's not compiler-independent, so you'll need some carefully placed#define
s to select which to use.
– Mike Seymour
Feb 11 '13 at 19:48
@MikeSymour if I use the boost Mutex for example (or any other Mutex), will that make the code thread-safe for other parallelization libraries, like OpenMPI and OpemMP? or does Mutex work exclusively for the parallelism of the library from which the Mutex is taken?
– The Quantum Physicist
Feb 12 '13 at 7:46
1
@SamerAfach: I don't quite understand the question, but I guess the answer is yes. Using a mutex correctly will serialise all sections of code that run with that mutex locked, making that code thread-safe, regardless of whatever parallelisation libraries you're using.
– Mike Seymour
Feb 14 '13 at 10:58
"regardless of whatever parallelisation libraries you're using". That answers my question. Thanks :)
– The Quantum Physicist
Feb 14 '13 at 11:03
add a comment |
Is it thread-safe?
Certainly not. If a thread is preempted between checking and setting the lock, then a second thread could acquire that lock; if control then returns to the first thread, then both will acquire it. (And of course, on a modern processor, two or more cores could be executing the same instructions simultaneously for even more hilarity.)
At the very least, you need an atomic test-and-set operation to implement a lock like this. The C++11 library provides such a thing:
std::atomic_flag locked;
if (!locked.test_and_set()) {
vals.push_back(val);
locked.clear();
} else {
// I don't know exactly what to do here;
// but recursively calling add() is a very bad idea.
}
or better yet:
std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
vals.push_back(val);
If you have an older implementation, then you'll have to rely on whatever extensions/libraries are available to you, as there was nothing helpful in the language or standard library back then.
hmmmmm. Thanks for the answers. I'm using VS2010 and g++, where the first one doesn't support mutex. Any other compiler independent idea?
– The Quantum Physicist
Feb 11 '13 at 19:42
1
@SamerAfach: The Boost.Thread and just::thread libraries have portable and (more or less) direct replacements for the C++11 mutex. Failing that there's the Windows API (critical sections, or whatever they call it); obviously that's not compiler-independent, so you'll need some carefully placed#define
s to select which to use.
– Mike Seymour
Feb 11 '13 at 19:48
@MikeSymour if I use the boost Mutex for example (or any other Mutex), will that make the code thread-safe for other parallelization libraries, like OpenMPI and OpemMP? or does Mutex work exclusively for the parallelism of the library from which the Mutex is taken?
– The Quantum Physicist
Feb 12 '13 at 7:46
1
@SamerAfach: I don't quite understand the question, but I guess the answer is yes. Using a mutex correctly will serialise all sections of code that run with that mutex locked, making that code thread-safe, regardless of whatever parallelisation libraries you're using.
– Mike Seymour
Feb 14 '13 at 10:58
"regardless of whatever parallelisation libraries you're using". That answers my question. Thanks :)
– The Quantum Physicist
Feb 14 '13 at 11:03
add a comment |
Is it thread-safe?
Certainly not. If a thread is preempted between checking and setting the lock, then a second thread could acquire that lock; if control then returns to the first thread, then both will acquire it. (And of course, on a modern processor, two or more cores could be executing the same instructions simultaneously for even more hilarity.)
At the very least, you need an atomic test-and-set operation to implement a lock like this. The C++11 library provides such a thing:
std::atomic_flag locked;
if (!locked.test_and_set()) {
vals.push_back(val);
locked.clear();
} else {
// I don't know exactly what to do here;
// but recursively calling add() is a very bad idea.
}
or better yet:
std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
vals.push_back(val);
If you have an older implementation, then you'll have to rely on whatever extensions/libraries are available to you, as there was nothing helpful in the language or standard library back then.
Is it thread-safe?
Certainly not. If a thread is preempted between checking and setting the lock, then a second thread could acquire that lock; if control then returns to the first thread, then both will acquire it. (And of course, on a modern processor, two or more cores could be executing the same instructions simultaneously for even more hilarity.)
At the very least, you need an atomic test-and-set operation to implement a lock like this. The C++11 library provides such a thing:
std::atomic_flag locked;
if (!locked.test_and_set()) {
vals.push_back(val);
locked.clear();
} else {
// I don't know exactly what to do here;
// but recursively calling add() is a very bad idea.
}
or better yet:
std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
vals.push_back(val);
If you have an older implementation, then you'll have to rely on whatever extensions/libraries are available to you, as there was nothing helpful in the language or standard library back then.
edited Feb 11 '13 at 19:07
answered Feb 11 '13 at 19:00
Mike SeymourMike Seymour
216k19342558
216k19342558
hmmmmm. Thanks for the answers. I'm using VS2010 and g++, where the first one doesn't support mutex. Any other compiler independent idea?
– The Quantum Physicist
Feb 11 '13 at 19:42
1
@SamerAfach: The Boost.Thread and just::thread libraries have portable and (more or less) direct replacements for the C++11 mutex. Failing that there's the Windows API (critical sections, or whatever they call it); obviously that's not compiler-independent, so you'll need some carefully placed#define
s to select which to use.
– Mike Seymour
Feb 11 '13 at 19:48
@MikeSymour if I use the boost Mutex for example (or any other Mutex), will that make the code thread-safe for other parallelization libraries, like OpenMPI and OpemMP? or does Mutex work exclusively for the parallelism of the library from which the Mutex is taken?
– The Quantum Physicist
Feb 12 '13 at 7:46
1
@SamerAfach: I don't quite understand the question, but I guess the answer is yes. Using a mutex correctly will serialise all sections of code that run with that mutex locked, making that code thread-safe, regardless of whatever parallelisation libraries you're using.
– Mike Seymour
Feb 14 '13 at 10:58
"regardless of whatever parallelisation libraries you're using". That answers my question. Thanks :)
– The Quantum Physicist
Feb 14 '13 at 11:03
add a comment |
hmmmmm. Thanks for the answers. I'm using VS2010 and g++, where the first one doesn't support mutex. Any other compiler independent idea?
– The Quantum Physicist
Feb 11 '13 at 19:42
1
@SamerAfach: The Boost.Thread and just::thread libraries have portable and (more or less) direct replacements for the C++11 mutex. Failing that there's the Windows API (critical sections, or whatever they call it); obviously that's not compiler-independent, so you'll need some carefully placed#define
s to select which to use.
– Mike Seymour
Feb 11 '13 at 19:48
@MikeSymour if I use the boost Mutex for example (or any other Mutex), will that make the code thread-safe for other parallelization libraries, like OpenMPI and OpemMP? or does Mutex work exclusively for the parallelism of the library from which the Mutex is taken?
– The Quantum Physicist
Feb 12 '13 at 7:46
1
@SamerAfach: I don't quite understand the question, but I guess the answer is yes. Using a mutex correctly will serialise all sections of code that run with that mutex locked, making that code thread-safe, regardless of whatever parallelisation libraries you're using.
– Mike Seymour
Feb 14 '13 at 10:58
"regardless of whatever parallelisation libraries you're using". That answers my question. Thanks :)
– The Quantum Physicist
Feb 14 '13 at 11:03
hmmmmm. Thanks for the answers. I'm using VS2010 and g++, where the first one doesn't support mutex. Any other compiler independent idea?
– The Quantum Physicist
Feb 11 '13 at 19:42
hmmmmm. Thanks for the answers. I'm using VS2010 and g++, where the first one doesn't support mutex. Any other compiler independent idea?
– The Quantum Physicist
Feb 11 '13 at 19:42
1
1
@SamerAfach: The Boost.Thread and just::thread libraries have portable and (more or less) direct replacements for the C++11 mutex. Failing that there's the Windows API (critical sections, or whatever they call it); obviously that's not compiler-independent, so you'll need some carefully placed
#define
s to select which to use.– Mike Seymour
Feb 11 '13 at 19:48
@SamerAfach: The Boost.Thread and just::thread libraries have portable and (more or less) direct replacements for the C++11 mutex. Failing that there's the Windows API (critical sections, or whatever they call it); obviously that's not compiler-independent, so you'll need some carefully placed
#define
s to select which to use.– Mike Seymour
Feb 11 '13 at 19:48
@MikeSymour if I use the boost Mutex for example (or any other Mutex), will that make the code thread-safe for other parallelization libraries, like OpenMPI and OpemMP? or does Mutex work exclusively for the parallelism of the library from which the Mutex is taken?
– The Quantum Physicist
Feb 12 '13 at 7:46
@MikeSymour if I use the boost Mutex for example (or any other Mutex), will that make the code thread-safe for other parallelization libraries, like OpenMPI and OpemMP? or does Mutex work exclusively for the parallelism of the library from which the Mutex is taken?
– The Quantum Physicist
Feb 12 '13 at 7:46
1
1
@SamerAfach: I don't quite understand the question, but I guess the answer is yes. Using a mutex correctly will serialise all sections of code that run with that mutex locked, making that code thread-safe, regardless of whatever parallelisation libraries you're using.
– Mike Seymour
Feb 14 '13 at 10:58
@SamerAfach: I don't quite understand the question, but I guess the answer is yes. Using a mutex correctly will serialise all sections of code that run with that mutex locked, making that code thread-safe, regardless of whatever parallelisation libraries you're using.
– Mike Seymour
Feb 14 '13 at 10:58
"regardless of whatever parallelisation libraries you're using". That answers my question. Thanks :)
– The Quantum Physicist
Feb 14 '13 at 11:03
"regardless of whatever parallelisation libraries you're using". That answers my question. Thanks :)
– The Quantum Physicist
Feb 14 '13 at 11:03
add a comment |
No, this is not thread safe. There's a race between
if(!locked)
and
this->locked = 1;
If there is a context switch between these two statements, your lock mechanism falls apart. You need an atomic test and set
instruction, or simply use an existing mutex
.
add a comment |
No, this is not thread safe. There's a race between
if(!locked)
and
this->locked = 1;
If there is a context switch between these two statements, your lock mechanism falls apart. You need an atomic test and set
instruction, or simply use an existing mutex
.
add a comment |
No, this is not thread safe. There's a race between
if(!locked)
and
this->locked = 1;
If there is a context switch between these two statements, your lock mechanism falls apart. You need an atomic test and set
instruction, or simply use an existing mutex
.
No, this is not thread safe. There's a race between
if(!locked)
and
this->locked = 1;
If there is a context switch between these two statements, your lock mechanism falls apart. You need an atomic test and set
instruction, or simply use an existing mutex
.
answered Feb 11 '13 at 18:59
Olaf DietscheOlaf Dietsche
56.9k565144
56.9k565144
add a comment |
add a comment |
This code doesn't provide an atomic modification of vals
vector. Consider the following scenario:
//<<< Suppose it's 0
if(!locked)
{ //<<< Thread 0 passes the check
//<<< Context Switch - and Thread 1 is also there because locked is 0
this->locked = 1;
//<<< Now it's possible for one thread to be scheduled when another one is in
//<<< the middle of modification of the vector
this->vals.push_back(val);
this->locked = 0;
}
add a comment |
This code doesn't provide an atomic modification of vals
vector. Consider the following scenario:
//<<< Suppose it's 0
if(!locked)
{ //<<< Thread 0 passes the check
//<<< Context Switch - and Thread 1 is also there because locked is 0
this->locked = 1;
//<<< Now it's possible for one thread to be scheduled when another one is in
//<<< the middle of modification of the vector
this->vals.push_back(val);
this->locked = 0;
}
add a comment |
This code doesn't provide an atomic modification of vals
vector. Consider the following scenario:
//<<< Suppose it's 0
if(!locked)
{ //<<< Thread 0 passes the check
//<<< Context Switch - and Thread 1 is also there because locked is 0
this->locked = 1;
//<<< Now it's possible for one thread to be scheduled when another one is in
//<<< the middle of modification of the vector
this->vals.push_back(val);
this->locked = 0;
}
This code doesn't provide an atomic modification of vals
vector. Consider the following scenario:
//<<< Suppose it's 0
if(!locked)
{ //<<< Thread 0 passes the check
//<<< Context Switch - and Thread 1 is also there because locked is 0
this->locked = 1;
//<<< Now it's possible for one thread to be scheduled when another one is in
//<<< the middle of modification of the vector
this->vals.push_back(val);
this->locked = 0;
}
answered Feb 11 '13 at 19:03
Maksim SkurydzinMaksim Skurydzin
7,49663149
7,49663149
add a comment |
add a comment |
Does this work? Is it thread-safe?
No. It will fail at times.
Your mutex will only work if other threads never do anything between the execution of these two lines:
if(!locked)
{
this->locked = 1;
...and you have not ensured that.
To learn about the how of mutex writing, see this SO post.
add a comment |
Does this work? Is it thread-safe?
No. It will fail at times.
Your mutex will only work if other threads never do anything between the execution of these two lines:
if(!locked)
{
this->locked = 1;
...and you have not ensured that.
To learn about the how of mutex writing, see this SO post.
add a comment |
Does this work? Is it thread-safe?
No. It will fail at times.
Your mutex will only work if other threads never do anything between the execution of these two lines:
if(!locked)
{
this->locked = 1;
...and you have not ensured that.
To learn about the how of mutex writing, see this SO post.
Does this work? Is it thread-safe?
No. It will fail at times.
Your mutex will only work if other threads never do anything between the execution of these two lines:
if(!locked)
{
this->locked = 1;
...and you have not ensured that.
To learn about the how of mutex writing, see this SO post.
edited May 23 '17 at 11:48
Community♦
11
11
answered Feb 11 '13 at 18:58
Drew DormannDrew Dormann
41.9k979142
41.9k979142
add a comment |
add a comment |
No, that is not thread safe.
Consider two threads running myclass::add
at more-or-less the same time. Also, imagine that the value of .locked
is false
.
The first thread executes up to and including this line:
if(!locked)
{
Now imagine that the system switches context to the second thread. It also executes up to the same line.
Now we have two different threads, both believing that they have exclusive access, and both inside the !locked
condition of the if.
They will both call vals.push_back()
at more-or-less the same time.
Boom.
add a comment |
No, that is not thread safe.
Consider two threads running myclass::add
at more-or-less the same time. Also, imagine that the value of .locked
is false
.
The first thread executes up to and including this line:
if(!locked)
{
Now imagine that the system switches context to the second thread. It also executes up to the same line.
Now we have two different threads, both believing that they have exclusive access, and both inside the !locked
condition of the if.
They will both call vals.push_back()
at more-or-less the same time.
Boom.
add a comment |
No, that is not thread safe.
Consider two threads running myclass::add
at more-or-less the same time. Also, imagine that the value of .locked
is false
.
The first thread executes up to and including this line:
if(!locked)
{
Now imagine that the system switches context to the second thread. It also executes up to the same line.
Now we have two different threads, both believing that they have exclusive access, and both inside the !locked
condition of the if.
They will both call vals.push_back()
at more-or-less the same time.
Boom.
No, that is not thread safe.
Consider two threads running myclass::add
at more-or-less the same time. Also, imagine that the value of .locked
is false
.
The first thread executes up to and including this line:
if(!locked)
{
Now imagine that the system switches context to the second thread. It also executes up to the same line.
Now we have two different threads, both believing that they have exclusive access, and both inside the !locked
condition of the if.
They will both call vals.push_back()
at more-or-less the same time.
Boom.
answered Feb 11 '13 at 18:59
RobᵩRobᵩ
117k13140222
117k13140222
add a comment |
add a comment |
Others have already shown how your mutex can fail, so I won't rehash their points. I will only add one thing: The simplest mutex implementation is a lot more complicated than your code.
If you're interested in the nitty gritty (or even if you are not - this is stuff every software developer should know) you should look at Leslie Lamport's Bakery Algorithm and go from there.
add a comment |
Others have already shown how your mutex can fail, so I won't rehash their points. I will only add one thing: The simplest mutex implementation is a lot more complicated than your code.
If you're interested in the nitty gritty (or even if you are not - this is stuff every software developer should know) you should look at Leslie Lamport's Bakery Algorithm and go from there.
add a comment |
Others have already shown how your mutex can fail, so I won't rehash their points. I will only add one thing: The simplest mutex implementation is a lot more complicated than your code.
If you're interested in the nitty gritty (or even if you are not - this is stuff every software developer should know) you should look at Leslie Lamport's Bakery Algorithm and go from there.
Others have already shown how your mutex can fail, so I won't rehash their points. I will only add one thing: The simplest mutex implementation is a lot more complicated than your code.
If you're interested in the nitty gritty (or even if you are not - this is stuff every software developer should know) you should look at Leslie Lamport's Bakery Algorithm and go from there.
answered Feb 11 '13 at 19:05
Nik BougalisNik Bougalis
9,71211734
9,71211734
add a comment |
add a comment |
You cannot implement it in C++. You have to use LOCK CMPXCHG. Here is my answer from here:
; BL is the mutex id
; shared_val, a memory address
CMP [shared_val],BL ; Perhaps it is locked to us anyway
JZ .OutLoop2
.Loop1:
CMP [shared_val],0xFF ; Free
JZ .OutLoop1 ; Yes
pause ; equal to rep nop.
JMP .Loop1 ; Else, retry
.OutLoop1:
; Lock is free, grab it
MOV AL,0xFF
LOCK CMPXCHG [shared_val],BL
JNZ .Loop1 ; Write failed
.OutLoop2: ; Lock Acquired
add a comment |
You cannot implement it in C++. You have to use LOCK CMPXCHG. Here is my answer from here:
; BL is the mutex id
; shared_val, a memory address
CMP [shared_val],BL ; Perhaps it is locked to us anyway
JZ .OutLoop2
.Loop1:
CMP [shared_val],0xFF ; Free
JZ .OutLoop1 ; Yes
pause ; equal to rep nop.
JMP .Loop1 ; Else, retry
.OutLoop1:
; Lock is free, grab it
MOV AL,0xFF
LOCK CMPXCHG [shared_val],BL
JNZ .Loop1 ; Write failed
.OutLoop2: ; Lock Acquired
add a comment |
You cannot implement it in C++. You have to use LOCK CMPXCHG. Here is my answer from here:
; BL is the mutex id
; shared_val, a memory address
CMP [shared_val],BL ; Perhaps it is locked to us anyway
JZ .OutLoop2
.Loop1:
CMP [shared_val],0xFF ; Free
JZ .OutLoop1 ; Yes
pause ; equal to rep nop.
JMP .Loop1 ; Else, retry
.OutLoop1:
; Lock is free, grab it
MOV AL,0xFF
LOCK CMPXCHG [shared_val],BL
JNZ .Loop1 ; Write failed
.OutLoop2: ; Lock Acquired
You cannot implement it in C++. You have to use LOCK CMPXCHG. Here is my answer from here:
; BL is the mutex id
; shared_val, a memory address
CMP [shared_val],BL ; Perhaps it is locked to us anyway
JZ .OutLoop2
.Loop1:
CMP [shared_val],0xFF ; Free
JZ .OutLoop1 ; Yes
pause ; equal to rep nop.
JMP .Loop1 ; Else, retry
.OutLoop1:
; Lock is free, grab it
MOV AL,0xFF
LOCK CMPXCHG [shared_val],BL
JNZ .Loop1 ; Write failed
.OutLoop2: ; Lock Acquired
answered Jan 2 at 9:09
MichaelMichael
1,4591836
1,4591836
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f14818915%2fsimplest-mutex-ever-does-this-example-work-is-it-thread-safe%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
5
Making a correct mutex mechanism is a complex business. I would use something already out there.
– andre
Feb 11 '13 at 18:57
Generally, synchronization primitives such as mutexes require some atomicity (often at the CPU instruction level). Here's an interesting link I found: lists.canonical.org/pipermail/kragen-tol/1999-August/…
– Tom
Feb 11 '13 at 19:06
The simplest mutex (or synchronization construct in general) is the one you don't need ;-)
– user395760
Feb 11 '13 at 19:16