Google Interview Question
SDE1sInterview Type: In-Person
In Java/C++ we would declare owner variable volatile, I suppose.
from threading import Lock, current_thread, Thread
def get_thread_id():
return id(current_thread())
class RLock(object):
def __init__(self):
self.lock = Lock()
self.owner = None
self.count = 0
def acquire(self):
current = get_thread_id()
if self.owner == current:
self.count += 1
else:
self.lock.acquire()
assert self.owner is None
self.owner = current
self.count = 1
def release(self):
current = get_thread_id()
assert self.owner == current
assert self.count > 0
self.count -= 1
if not self.count:
self.owner = None
self.lock.release()
def __enter__(self):
self.acquire()
def __exit__(self, tp, val, tb):
self.release()
rlock = RLock()
def factorial(n):
with rlock:
if n <= 0:
return 1
else:
return n * factorial(n - 1)
rlock = RLock()
shared = 0
def repeat(times, n):
for i in xrange(times):
add_numbers(n)
def add_numbers(n):
global shared
with rlock:
result = 0
if n <= 1:
result = 1
else:
result = n
add_numbers(n - 1)
shared += result
num_threads = 5
iterations = 100000
depth = 10
threads = [Thread(target=repeat, args=(iterations, depth))
for _ in xrange(num_threads)]
[t.start() for t in threads]
[t.join() for t in threads]
assert shared == num_threads * iterations * depth * (depth + 1) / 2
package com.devinline.locking;
/*
* For sake of simplicity - assume custom lock interface having only three
* methods.
*/
interface CustomLock {
public void lock();
public boolean tryLock();
public void unlock();
}
public class CustomReentrantLock implements CustomLock {
/* Maintain number of locks acquired by a thread */
int lockHoldCount;
/* Id of thread which is currently holding the lock. */
long threadId;
/**
* Creates an instance of CustomReentrantLock and Initial lock hold count is
* 0.
*/
CustomReentrantLock() {
lockHoldCount = 0;
}
@Override
public synchronized void lock() {
/*
* Acquires the lock if it is not held by another thread and set lock
* hold count to 1.
*/
if (lockHoldCount == 0) {
lockHoldCount++;
threadId = Thread.currentThread().getId();
}
/*
* If current thread already holds lock then hold count is increased by
* 1 - Chain locking.
*/
else if (lockHoldCount > 0
&& threadId == Thread.currentThread().getId()) {
lockHoldCount++;
}
// If the lock is held by another thread then the current
// thread waits for another thread to release lock.
else {
try {
wait();
lockHoldCount++;
threadId = Thread.currentThread().getId();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public synchronized void unlock() {
/*
* If current thread is not holding the lock, if unlock is called it
* throws IllegalMonitorStateException.
*/
if (lockHoldCount == 0)
throw new IllegalMonitorStateException();
/* If lock is held, decrement lock hold count by 1 */
lockHoldCount--;
/*
* If lockHoldCount is 0, lock is released and waiting thread is
* notified.
*/
if (lockHoldCount == 0)
notify();
}
@Override
public synchronized boolean tryLock() {
/*
* Acquires the lock if it is not held by another thread and // returns
* true
*/
if (lockHoldCount == 0) {
lock();
return true;
}
// If lock is held by another thread then method return false.
else
return false;
}
}
package com.devinline.locking;
/*
* For sake of simplicity - assume custom lock interface having only three
* methods.
*/
interface CustomLock {
public void lock();
public boolean tryLock();
public void unlock();
}
public class CustomReentrantLock implements CustomLock {
/* Maintain number of locks acquired by a thread */
int lockHoldCount;
/* Id of thread which is currently holding the lock. */
long threadId;
/**
* Creates an instance of CustomReentrantLock and Initial lock hold count is
* 0.
*/
CustomReentrantLock() {
lockHoldCount = 0;
}
@Override
public synchronized void lock() {
/*
* Acquires the lock if it is not held by another thread and set lock
* hold count to 1.
*/
if (lockHoldCount == 0) {
lockHoldCount++;
threadId = Thread.currentThread().getId();
}
/*
* If current thread already holds lock then hold count is increased by
* 1 - Chain locking.
*/
else if (lockHoldCount > 0
&& threadId == Thread.currentThread().getId()) {
lockHoldCount++;
}
// If the lock is held by another thread then the current
// thread waits for another thread to release lock.
else {
try {
wait();
lockHoldCount++;
threadId = Thread.currentThread().getId();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public synchronized void unlock() {
/*
* If current thread is not holding the lock, if unlock is called it
* throws IllegalMonitorStateException.
*/
if (lockHoldCount == 0)
throw new IllegalMonitorStateException();
/* If lock is held, decrement lock hold count by 1 */
lockHoldCount--;
/*
* If lockHoldCount is 0, lock is released and waiting thread is
* notified.
*/
if (lockHoldCount == 0)
notify();
}
@Override
public synchronized boolean tryLock() {
/*
* Acquires the lock if it is not held by another thread and // returns
* true
*/
if (lockHoldCount == 0) {
lock();
return true;
}
// If lock is held by another thread then method return false.
else
return false;
}
}
Lock lock = new Lock();
Condition condition = lock.newCondition();
boolean isLockHeld=false;
int threadId=-1;
int lockCount;
public void lock(){
lock.lock();
if(isLockHeld){
if(threadId==Thread.currentThread.getId()){
lockCount++;
}else{
while(isLockHeld){
condition.await();
}
lockCount++;
threadId=Thread.currentThread().getId();
isLockHeld=true;
}
}
lock.unlock();
}
}
public void unlock(){
lock.lock();
if(isLockHeld && threadId==Thread.currentThread().getId()){
lockCount - -;
if(lockCount==0){
threadId=-1;
isLockHeld=false;
condition.notifyAll();
}
}
lock.unlock();
}
A Re-EntrantLock is owned by the thread last successfully locking, but not yet unlocking it. A thread invoking lock will return, successfully acquiring the lock, when the lock is not owned by another thread. The method will return immediately if the current thread already owns the lock.
- R@M3$H.N November 09, 2015