Lock, semaphore, condition variables and monitors.

How to pick between locks, semaphores, condvars, monitors?
     Locks are very simple for many cases(spinlock is used in kernel space for very simple content.)
        Issues: Maybe not the most efficient solution.
            For example, can't allow multiple readers but one writer inside a standard lock.
     Condition variables allow threads to sleep while holding a lock.
        Just be sure you understand whether they use Mesa(re-check condition when wakes up) or Hoare semntics.
Checks wait condition first, sends necessary signal at the end of procedure.
     Semaphores provide pretty general functionality
        But also make it really easy to botch things up.
     Monitors(e.g. synchronized in Java) are a "pattern" for using locks and condition variables that is often very useful.


Semaphore:
     Down operation on a semaphore checks to see if the value is greater than 0, if so, it decrements the value and just continues.
    If the value is 0, the process is put to sleep( sleeping queue) without completing the down for the moment.
    
     Up operation increments the value of the semaphore addressed, if one or more process were sleeping on that semaphore, unable to complete an earlier down operation, one of them is chosen by the system and is allowed to complete its down.
    Thus, after an up on a semaphore with processes sleeping on it, the operation of incrementing the semaphore and waking up one process is also indivisible.
    No process ever blocks doing an up.
    Binary semaphore essentially the same as a lock.

     Simple semaphore implementation
   
 struct semaphore {
        int val;
        thread_list waiting; //list of threads waiting for semaphore.
    };

    Down(sem):
        while(sem.val <= 0)    <span style="color:#ff0000;">//Another thread might call Down() while this thread is blocked, so we have to check the condition again when we wake back up. Don't use if statement at here.</span>
            sem.waiting.append(thread);
            block(thread);
        sem.val -= 1;
        return;

    Up(sem):
        sem.val += 1;
        if(!sem.waiting.empty())
            thread = sem.waiting.remove();
            wakeup(thread);

    Example of  producer/consumer:
    
semaphore mutex = 1;    //init value is very important.
    semaphore empty = N;
    semaphore full = 0;

    producer()
        while(true)
            item = produce_item()
            down(&empty)    //blocked process adds to sleeping queue
            down(&mutex)
            insert_item()
            up(&mutex)
            up(&full)

    consumer()
        while(true)
            down(&full)
            down(&mutex)
            item = remove_item()
            insert_item()
            up(&mutex)
            up(&empty)    //wake up sleeping processes from sleeping queue random, never block process.
            consume_item(item);


     Reader/Writer
   
    semaphore mutex = 1;    //protect readcount.
    semaphore wrt = 1;
    int    readcount = 0;

    writer():
        Down(wrt)
        do_write()
        Up(wrt)

    Reader():
        Down(mutex)
        if (++readcount == 1)
            Down(wrt)
        Up(mutex)
        do_read()
        Down(mutex)
        if (--readcount == 0)
            Up(wrt)
        Up(mutex)


    Futex:     
        fast user space mutex, avoid context swtich(expensive system call) until it is needed. 
        kernel service provides a " wait queue" that allows multiple processes to wait on a lock. They will not run, unless the kernel explicitly unblocks them.
         kernel blocks threads until lock is available to avoid context switch.
        processs share a common lock variable(32-bit integer).

    Critical section(region):
        Section that the shared memory is accessed.

    Mutex:
        mutex is a shared variable(per-process) that is used to synchronize threads and protected critical region.

    Condition Mutex:
        Synchronization mechanism allows threads to block due to some condition not being met. Almost always is used with mutex.
        The pattern is for one thread to lock a mutex, then wait on a conditional variable when it cannot get what it needs. 
        pthread_cond_wait call atomically unlocks the mutex it is holding.
         condition variables(unlike semaphore) have no memory, signals may be lost(it's better to use broadcast to wakeup threads).
        Synchronization variable that can be signaled to tell the thread that the resource is available to avoid busy waiting.

    
Key ideas for CV:
    wait() on a CV releases the lock
    signal on a CV wakes up a thread waiting on a lock
    The thread that wakes up has to re-lock before wait returns then  recheck condition. 

    Semaphores integrate the state into atomic P/V primitives, but the only state that is supported is a simple counter.
    Condition variables(CVs) allow the program to define the condition/state, and t protect it with an integrated mutex.

    Semaphores vs. Condition Variables
    1. Up differs from Signal in that:
        1). Signal has no effect if no thread is waiting on the condition(lost). 
        Condition variables are not variables, they have no value.
        2). Up has the same effect whether or not a thread is waiting.
        Semaphores retain a "memory" of calls to Up.
    2. Down differs from Wait in that:
        1). Down checks the condition and blocks only if necessary.
        No need to recheck the condition after returning from Down wait condition is defined internally, but is limited to a counter.
        2). Wait is explicit: it does not check the condition, ever.
        condition is defined externally and protected by intergrated mutex.

    Semaphores using Condition variables.
    void Down() {
        mutex->acquire();
        assert(count >= 0);
        while(count == 0)
            condition->wait(mutex);
        count -= 1;
        mutex->release();
    }

    void Up() {
        mutex->acquire();
        count += 1;
        condition->signal(mutex);
        mutex->release();
    }
        Condition variable: one or more threads waiting on a single particular condition(e.g. for queue to be empty)
        Semaphores are good for producer/consumer situations. Shared resource that can be availabe or unavailable based on some integer number of available things.

        
     Monitors:
    The style of using locks and CV's to protect access to a shared object is often called a monitor.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值