同步机制--->互斥锁

      互斥锁指代相互排斥,它是最基本的同步形式。互斥锁用于保护临界区,以保证任何时刻只有一个线程在执行其中的代码,或者任何一个时刻只有一个进程在执行其中的代码。保护一个临界区的代码的通常轮廓大体如下:

     lock_the_mutex(...)

     临界区

     unlock_the_mutex(...)

    Posix互斥锁被声明为具有pthread_mutex_t 数据类型的变量。如果互斥锁变量是静态分配的,那么我们可以把它初始化成常值PTHREAD_MUTEX_INITIALIZER,例如:

    static  pthread_mutex_t   lock = PTHREAD_MUTEX_INITIALIZER

    如果互斥锁是动态分配的(例如通过调用malloc)或者分配在共享内存区中,那么我们必须在运行之时通过调用pthread_mutex_init函数来初始化它。

    下列三个函数给一个互斥锁上锁和解锁。

     #include<pthread.h>

     int  pthread_mutex_lock(pthread_mutex_t *mptr)

     int  pthread_mutex_trylock(pthread_mutex_t * nptr)

     int  pthread_mutex_unlock(pthread_mutex_t  * mptr)

        均返回:若成功返回0,若出错返回正的Exxx值

     如果尝试一个已由另外一个线程锁住的互斥锁上锁,那么pthread_mutex_lock将阻塞到该互斥锁解锁为止。pthread_mutex_trylock是对应的非阻塞函数,如果该互斥锁已锁住,它就返回一个EBUSY错误。

      尽管我们说互斥锁保护的是临界区,实际上保护的是在临界区中被操纵的数据。也就是说,互斥锁通常用于保护由多个线程和多个进程分享的共享数据

       (一、)生产者-消费者问题

     在单个进程中有多个生产者线程和单个消费者线程。整数数组buff含有被生产和消费的条目(也就是共享数据),在第一个例子中,我们只关心多个生产者线程之间的同步。直到所有生产者线程都生产完成工作后,我们才启动消费者线程。

    其代码如下:

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>

#define MAXNITEMS 1000
#define MAXNTHREADS 100

int nitems;

struct{
    pthread_mutex_t mutex;
    int buff[MAXNITEMS];
    int nput;
    int nval;
}shared = {PTHREAD_MUTEX_INITIALIZER};

int min(const int a,const int b)
{
    return (a > b ? b : a);
}
void * produce(void *arg)
{
    for(;;)
    {
        pthread_mutex_lock(&shared.mutex);
        if(shared.nput >= nitems)
        {
            pthread_mutex_unlock(&shared.mutex);
            return (NULL);
        }

        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 0
        if(shared.buff[i] != i)
        {
            printf("buff[%d] = %d\n",i,shared.buff[i]);
        }
        #endif
        printf("buff[%d] = %d\n",i,shared.buff[i]);
    }
    return (NULL);
}

int main(int argc,char*argv[])
{
    int i;
    int nthreads, count[MAXNTHREADS];
    pthread_t tid_produce[MAXNTHREADS],tid_consume;

    if(argc != 3)
    {
        printf("usage: prodcons<# items> <# threads>\n");
        exit(1);
    }

    nitems = min(atoi(argv[1]),MAXNITEMS);
    nthreads = min(atoi(argv[2]),MAXNTHREADS);

    pthread_setconcurrency(nthreads);
    
    for(i = 0; i < nthreads; ++i)
    {
        count[i] = 0;
        pthread_create(&tid_produce[i],NULL,produce,&count[i]);
        sleep(1);
    }

    for(i = 0; i < nthreads; ++i)
    {
        pthread_join(tid_produce[i],NULL);
        printf("count[%d] = %d\n",i,count[i]);
    }

    pthread_create(&tid_consume,NULL,consume,NULL);
    pthread_join(tid_consume,NULL);
    return 0;
}

其执行结果:

  对比上锁与等待:

      现在展示互斥锁用于上锁而不用于等待。我们把上一节的生产者-消费者例子改为在所有生产者线程都启动后立即启动消费者线程。这样在生产者线程产生数据的同时,消费者线程就能处理它,而不是像之前那样,消费者线程直到所有生产者线程都完成后才启动。下面给出具体的代码:

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>

#define MAXNITEMS 1000
#define MAXNTHREADS 100

int nitems;

struct{
    pthread_mutex_t mutex;
    int buff[MAXNITEMS];
    int nput;
    int nval;
}shared = {PTHREAD_MUTEX_INITIALIZER};

int min(const int a,const int b)
{
    return (a > b ? b : a);
}
void * produce(void *arg)
{
    for(;;)
    {
        pthread_mutex_lock(&shared.mutex);
        if(shared.nput >= nitems)
        {
            pthread_mutex_unlock(&shared.mutex);
            return (NULL);
        }

        shared.buff[shared.nput] = shared.nval;
        shared.nput++;
        shared.nval++;
        pthread_mutex_unlock(&shared.mutex);
        *((int *)arg) += 1;
    }
}

void consume_wait(int i)
{
    for(;;)
    {
        pthread_mutex_lock(&shared.mutex);
        if(i < shared.nput)
        {
            pthread_mutex_unlock(&shared.mutex);
            return ;
        }
        pthread_mutex_unlock(&shared.mutex);
    }
}



void * consume(void *arg)
{
    int i;
    for(i = 0; i < nitems; ++i)
    {
        consume_wait(i);
        printf("buff[%d] = %d\n",i,shared.buff[i]);
    }
    return (NULL);
}

int main(int argc,char*argv[])
{
    int i;
    int nthreads, count[MAXNTHREADS];
    pthread_t tid_produce[MAXNTHREADS],tid_consume;

    if(argc != 3)
    {
        printf("usage: prodcons<# items> <# threads>\n");
        exit(1);
    }

    nitems = min(atoi(argv[1]),MAXNITEMS);
    nthreads = min(atoi(argv[2]),MAXNTHREADS);

    pthread_setconcurrency(nthreads + 1);
    
    for(i = 0; i < nthreads; ++i)
    {
        count[i] = 0;
        pthread_create(&tid_produce[i],NULL,produce,&count[i]);
        sleep(1);
    }

    pthread_create(&tid_consume,NULL,consume,&count[i]);
    for(i = 0; i < nthreads; ++i)
    {
        pthread_join(tid_produce[i],NULL);
        printf("count[%d] = %d\n",i,count[i]);
    }

    pthread_join(tid_consume,NULL);
    return 0;
}

上述就是对互斥锁的一些基本的应用。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值