A few days ago I spent some time comparing Java synchronization primitives and those from POSIX thread library and found some differences from both the default behaviour and the terminology point of view.
Fist of all, java intrinsic locks are reentrant. It means that thread that already holds a lock can acquire the same lock. Without that property the thread would block when reacquiring the lock it already holds. POSIX locks ( or mutex variables) are not reentrant (of recursive) by default but can become reentant if properly configured.
I can illustrate that with the following example: the thread-safe class that allows setting x, y and both coordinates at the same time. Note, that this is just the example and real-time implementation would greatly differ.
// Point.java
public class Point {
private int x = 0;
private int y = 0;
public synchronized void setValue(int x, int y) {
setX(x);
setY(y);
}
public synchronized void setX(int x) {
this.x = x;
}
public synchronized void setY(int y) {
this.y = y;
}
public static void main(String[] args) {
Point p = new Point();
p.setValue(3, 5);
}
}
This example executes correnly and requring the object's intrinsic lock in the method setValue proceeds without any problems. But the similar example using POSIX threads will block if not configured in a special way:
// point.cpp
#include
class Point
{
public:
Point();
virtual ~Point();
void setX(int x);
void setY(int y);
void setValue(int x, int y);
private:
int _x;
int _y;
pthread_mutex_t _lock;
};
Point::Point() : _x(0), _y(0)
{
// initialize mutex lock
pthread_mutex_init(&_lock, NULL);
}
Point::~Point()
{
// destroy mutex lock
pthread_mutex_destroy(&_lock);
}
void Point::setX(int x)
{
if (pthread_mutex_lock(&_lock))
return;
_x = x;
pthread_mutex_unlock(&_lock);
}
void Point::setY(int y)
{
if (pthread_mutex_lock(&_lock))
return;
_y = y;
pthread_mutex_unlock(&_lock);
}
void Point::setValue(int x, int y)
{
if (pthread_mutex_lock(&_lock))
return;
setX(x);
setY(y);
pthread_mutex_unlock(&_lock);
}
int main()
{
Point p;
p.setValue(3, 5);
}
To achieve reentrancy with POSIX threads one can initialise the mutex (or lock) as follows:
Point::Point() : _x(0), _y(0)
{
// initialize mutex lock
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&_lock, &attr);
}