zoukankan      html  css  js  c++  java
  • Unix IPC之互斥锁与条件变量

    互斥锁

    1、函数声明

    #include <pthread.h>
    
    /* Mutex handling.  */
    
    /* Initialize a mutex.  */
    extern int pthread_mutex_init (pthread_mutex_t *__mutex,
                       __const pthread_mutexattr_t *__mutexattr)
         __THROW __nonnull ((1));
    
    /* Destroy a mutex.  */
    extern int pthread_mutex_destroy (pthread_mutex_t *__mutex)
         __THROW __nonnull ((1));
    
    /* Try locking a mutex.  */
    extern int pthread_mutex_trylock (pthread_mutex_t *__mutex)
         __THROW __nonnull ((1));
    
    /* Lock a mutex.  */
    extern int pthread_mutex_lock (pthread_mutex_t *__mutex)
         __THROW __nonnull ((1));
    /* Unlock a mutex. */ extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROW __nonnull ((1));

    2、函数使用

    pthread_mutex_lock(mutex);
    // 临界区
    // do something....
    // 临界区
    pthread_mutex_unlock(mutex);
    
    /**
     * 如果尝试给一个已由另外某个线程锁住的互斥锁上锁
     * pthread_mutex_lock将阻塞,直到该互斥锁解锁为止
     * pthread_mutex_trylock是对应的非阻塞函数,若互斥锁已锁住,则立即返回一个EBUSY错误
     */

    3、测试用例:

    /* include main */
    #include    "unpipc.h"
    
    #define MAXNITEMS       1000000
    #define MAXNTHREADS         100
    
    int     nitems;         /* read-only by producer and consumer */
    struct
    {
        pthread_mutex_t   mutex;
        int   buff[MAXNITEMS];
        int   nput; // 记录已写条目数目
        int   nval;
    } shared = { PTHREAD_MUTEX_INITIALIZER };
    
    void    *produce(void *);
    void    *consume(void *);
    
    int main(int argc, char **argv)
    {
        int         i, nthreads, count[MAXNTHREADS];
        pthread_t   tid_produce[MAXNTHREADS]; // 多生产者线程
        pthread_t   tid_consume; // 单消费者线程
    
        if (argc != 3)
            err_quit("usage: prodcons2 <#items> <#threads>");
        nitems = min(atoi(argv[1]), MAXNITEMS);
        nthreads = min(atoi(argv[2]), MAXNTHREADS);
    
        /* 最好调用pthread_setconcurrency函数 */
        Set_concurrency(nthreads); // 设置并行级别,大部分系统中该函数并没有什么作用
        /* 4start all the producer threads */
        for (i = 0; i < nthreads; i++)
        {
            count[i] = 0;
            Pthread_create(&tid_produce[i], NULL, produce, &count[i]);
        }
    
        /* 4wait for all the producer threads */
        for (i = 0; i < nthreads; i++)
        {
            Pthread_join(tid_produce[i], NULL);
            printf("count[%d] = %d
    ", i, count[i]);
        }
    
        /* 4start, then wait for the consumer thread */
        Pthread_create(&tid_consume, NULL, consume, NULL);
        Pthread_join(tid_consume, NULL);
    
        exit(0);
    }
    /* end main */
    
    /* include producer */
    void *produce(void *arg)
    {
        for ( ; ; )
        {
            Pthread_mutex_lock(&shared.mutex);
            if (shared.nput >= nitems)
            {
                Pthread_mutex_unlock(&shared.mutex);
                return(NULL);       /* array is full, we're done */
            }
            shared.buff[shared.nput] = shared.nval;
            shared.nput++;
            shared.nval++;
            Pthread_mutex_unlock(&shared.mutex);
            *((int *) arg) += 1; // 每个线程修改各自的元素
        }
    }
    
    void *consume(void *arg)
    {
        int     i;
    
        for (i = 0; i < nitems; i++)
        {
            if (shared.buff[i] != i)
                printf("buff[%d] = %d
    ", i, shared.buff[i]);
        }
        return(NULL);
    }
    /* end producer */
    View Code


    条件变量

    互斥锁用于上锁,条件变量用于等待,这是两种不同类型的同步。

    1、函数声明

    #include  <pthread.h>
    
    /* Wake up one thread waiting for condition variable COND.  */
    extern int pthread_cond_signal (pthread_cond_t *__cond)
         __THROW __nonnull ((1));
    
    /* Wake up all threads waiting for condition variables COND.  */
    extern int pthread_cond_broadcast (pthread_cond_t *__cond)
         __THROW __nonnull ((1));
    
    /* Wait for condition variable COND to be signaled or broadcast.
       MUTEX is assumed to be locked before.
    
       This function is a cancellation point and therefore not marked with
       __THROW.  */
    extern int pthread_cond_wait (pthread_cond_t *__restrict __cond,
                      pthread_mutex_t *__restrict __mutex)
         __nonnull ((1, 2));
    
    /* Wait for condition variable COND to be signaled or broadcast until
       ABSTIME.  MUTEX is assumed to be locked before.  ABSTIME is an
       absolute time specification; zero is the beginning of the epoch
       (00:00:00 GMT, January 1, 1970).
    
       This function is a cancellation point and therefore not marked with
       __THROW.  */
    extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
                       pthread_mutex_t *__restrict __mutex,
                       __const struct timespec *__restrict
                       __abstime) __nonnull ((1, 2, 3));

    2、函数使用

    struct
    {
        pthread_mutex_t   mutex;
        pthread_cond_t    cond;
        // ...
    } var = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER };
    
    /**
     * 给条件变量发送信号代码
     */
    Pthread_mutex_lock(&var.mutex);
    if(condition0 == true)
    {
        Pthread_cond_signal(&var.cond);
    }
    // do something...
    pthread_mutex_unlock(&var.mutex);
    
    /**
     * 测试条件变量
     */
    Pthread_mutex_lock(&var.mutex);
    while(condition1 == false) // 防止接收到错误信号
    {
        Pthread_cond_wait(&var.cond, &var.mutex);
    }
    // do something...
    pthread_mutex_unlock(&var.mutex);

    关于Pthread_cond_wait(&var.cond, &var.mutex)函数的说明

    The mutex passed to pthread_cond_wait protects the condition.The caller passes it locked to the function, which then atomically places them calling thread on the list of threads waiting for the condition and unlocks the mutex. This closes the window between the time that the condition is checked and the time that the thread goes to sleep waiting for the condition to change, so that the thread doesn't miss a change in the condition. When pthread_cond_wait returns, the mutex is again locked.

    上面是APUE的原话,就是说pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)函数传入的参数mutex用于保护条件,因为我们在调用pthread_cond_wait时,如果条件不成立我们就进入阻塞,但是进入阻塞这个期间,如果条件变量改变了的话,那我们就漏掉了这个条件。因为这个线程还没有放到等待队列上,所以调用pthread_cond_wait前要先锁互斥量,即调用pthread_mutex_lock(),pthread_cond_wait在把线程放进阻塞队列后,自动对mutex进行解锁,使得其它线程可以获得加锁的权利。这样其它线程才能对临界资源进行访问并在适当的时候唤醒这个阻塞的进程。当pthread_cond_wait返回的时候又自动给mutex加锁。
    // 函数执行期间锁的调用(伪码)
    lock(mutex)   ----------------a.lock
    
    pthread_cond_wait()
    {
        unlock(mutex)-------------a.unlock
        if (条件不满足)
          suspend();
        else 
        {
          lock(mutex)-------------b.lock
          return
        }
    }
    
    dosomething();
    
    unlock(mutex);---------------b.unlock

    3、测试用例

    /* include globals */
    #include    "unpipc.h"
    
    #define MAXNITEMS       1000000
    #define MAXNTHREADS         100
    
    /* globals shared by threads */
    int     nitems;             /* read-only by producer and consumer */
    int     buff[MAXNITEMS];
    struct
    {
        pthread_mutex_t   mutex;
        int               nput;   /* next index to store */
        int               nval;   /* next value to store */
    } put = { PTHREAD_MUTEX_INITIALIZER };
    
    struct
    {
        pthread_mutex_t   mutex;
        pthread_cond_t    cond;
        int               nready; /* number ready for consumer */
    } nready = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER };
    /* end globals */
    
    void    *produce(void *);
    void    *consume(void *);
    
    /* include main */
    int
    main(int argc, char **argv)
    {
        int         i, nthreads, count[MAXNTHREADS];
        pthread_t   tid_produce[MAXNTHREADS], tid_consume;
    
        if (argc != 3)
            err_quit("usage: prodcons6 <#items> <#threads>");
        nitems = min(atoi(argv[1]), MAXNITEMS);
        nthreads = min(atoi(argv[2]), MAXNTHREADS);
    
        Set_concurrency(nthreads + 1);
        /* 4create all producers and one consumer */
        for (i = 0; i < nthreads; i++)
        {
            count[i] = 0;
            Pthread_create(&tid_produce[i], NULL, produce, &count[i]);
        }
        Pthread_create(&tid_consume, NULL, consume, NULL);
    
        /* wait for all producers and the consumer */
        for (i = 0; i < nthreads; i++)
        {
            Pthread_join(tid_produce[i], NULL);
            printf("count[%d] = %d
    ", i, count[i]);
        }
        Pthread_join(tid_consume, NULL);
    
        exit(0);
    }
    /* end main */
    
    /* include prodcons */
    void *
    produce(void *arg)
    {
        for ( ; ; )
        {
            Pthread_mutex_lock(&put.mutex);
            if (put.nput >= nitems)
            {
                Pthread_mutex_unlock(&put.mutex);
                return(NULL);       /* array is full, we're done */
            }
            buff[put.nput] = put.nval;
            put.nput++;
            put.nval++;
            Pthread_mutex_unlock(&put.mutex);
    
            /* 同步生产者与消费者线程 */
            Pthread_mutex_lock(&nready.mutex);
            if (nready.nready == 0)
            {
                // 发送信号,系统调用等待在nready.cond上的线程
                // 该线程开始运行,但是立即停止,因为无法获取nready.mutex锁
                Pthread_cond_signal(&nready.cond);
            }
    
            nready.nready++;
            Pthread_mutex_unlock(&nready.mutex);
    
            *((int *) arg) += 1;
        }
    }
    
    void *
    consume(void *arg)
    {
        int     i;
    
        for (i = 0; i < nitems; i++)
        {
            Pthread_mutex_lock(&nready.mutex);
            while (nready.nready == 0) // 当产品数目为0时才会有线程阻塞,此时采用必要发送条件信号
            {
                Pthread_cond_wait(&nready.cond, &nready.mutex);
            }
    
            nready.nready--;
            Pthread_mutex_unlock(&nready.mutex);
    
            if (buff[i] != i)
                printf("buff[%d] = %d
    ", i, buff[i]);
        }
        return(NULL);
    }
    /* end prodcons */
    View Code


     

  • 相关阅读:
    第一章 第二节逻辑代数基础
    第一章 第一节数制与编码
    Altium Designer多原理图、PCB更新处理
    AD添加LOGO的方法
    XML中<beans>属性
    程序员值得学习的技术博客
    设计模式
    js分页实例
    Java构造和解析Json数据的方法
    H5+ 移动app学习之三 App离线存储
  • 原文地址:https://www.cnblogs.com/fengkang1008/p/4729493.html
Copyright © 2011-2022 走看看