Linux应用——线程(二)

目录

一、线程同步

二、互斥量

2.1概述        

2.2 互斥量相关操作函数

三、死锁

 3.1忘记释放锁

3.2重复加锁

3.3多线程多锁

四、读写锁

五、生产者消费者模型

六、条件变量

七、信号量

一、线程同步

        多线程中重要的内容。

案例:使用多线程卖票的案例,有3个窗口,100张票;

微观角度:并发执行;宏观角度:并行执行;

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void * sellticket(void * arg)
{
     int tickets=100;
    //卖票;
    while(tickets>0)
    {
       // usleep(7000);
        printf("%ld 正在卖第 %d 张票;\n",pthread_self(),tickets);
        tickets--;
    }
    return NULL;
}
int main()
{
    //创建三个子线程;
    pthread_t tid1,tid2,tid3;
    pthread_create(&tid1,NULL,sellticket,NULL);
    pthread_create(&tid2,NULL,sellticket,NULL);
    pthread_create(&tid3,NULL,sellticket,NULL);
    //回收子线程的资源,阻塞
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    pthread_join(tid3,NULL);
    pthread_exit(NULL);//退出主线程;

        return 0;
}

结果分析:

        三个线程各自卖了100张票, 但是需求是三个窗口一共100张,所以,结果并不是我们预想的那样。因为tickets作为局部变量,在函数里面,每个线程都有自己的局部变量,这样就有三个tickets。

修改为全局变量

//全局变量,所有的线程卖100张;

int tickets=100;

void * sellticket(void * arg)

    //卖票;

    while(tickets>0)

    {

        printf("%ld 正在卖第 %d 张票;\n",pthread_self(),tickets);

        tickets--;

    }

    return NULL;

}

运行结果:

        我们发现还是有问题,比如说第100张票卖了好几遍,这显然是不正确的。我们在程序中加上延时,这种现象会更加明显:     

void * sellticket(void * arg)

{

     

    //卖票;

    while(tickets>0)

    {

        usleep(7000);

        printf("%ld 正在卖第 %d 张票;\n",pthread_self(),tickets);

        tickets--;

    }

    return NULL;

}

运行结果:

        根据上面我们甚至发现出现了零票、负数票的现象,这是为什么呢?

        线程同步有关的问题,三个线程并发执行,抢占CPU资源,谁抢到就谁执行,这样会导致,同一个票数,ABC都进入卖票的程序,在票数没减之前,其他线程就会出票。

        多个线程对同一个资源做了同时的处理。那么如何处理这种问题?

        对于共享数据的操作同一个时间只能有一个线程进行操作。

        线程的主要优势在于,能够通过全局变量来共享信息,不过这种便捷的共享是有代价的:必须确保多个线程不会同时修改同一变量,或者某一线程不会读取正在有其他进程修改的变量。

临界区:访问某一共享资源的代码片段,并且这段代码的执行应为原子操作,也就是同时访问同一共享资源的其他线程不应终端该片段的执行。

线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该线程的内存地址进行操作,而其他线程则处于等待状态。

线程同步能降低代码的执行效率,但是这是必须的,因为这得保证代码的安全性;

二、互斥量

2.1概述        

为何解决线程数据的安全问题;

        为了避免线程更新共享变量出现问题,可以使用互斥量(mutex),来确保同时只有一个线程来访问某项共享资源。可以使用互斥量来保证任意共享资源的原子访问。

        互斥量有两种状态:已锁定和未锁定。

        任何时候,只有有一个线程可以锁定该互斥量。试图对已经锁定的某一互斥量再次进行加锁,将可能阻塞线程或者报错,具体取决于加锁时使用的方法;

        一旦线程锁定互斥量,随即称为该互斥量的所有者,只有所有者才能给互斥量解锁。一百清凉下,对每一共享资源(可能由多个相关变量组成)会使用不同的互斥量,每一个线程在访问同一资源时将采用如下协议:

        针对共享资源锁定互斥量;

        访问共享资源;

        对互斥量解锁;      

 如果多个新城试图执行这个代码(一个临界区),事实上只有一个线程能够持有该互斥量(其他线程将遭到阻塞),即同时只有一个线程能够进入这段代码区域:

2.2 互斥量相关操作函数

互斥量的类型 pthread_mutex_t

类似于变量的类型,使用互斥量需要先定义一个互斥量;
◼ int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);

初始化互斥量:

        参数:mutex:需要初始化的互斥量;

                   attr:互斥量相关属性-NULL;

          restrict:C语言修饰符。被修饰指针不能由另外的指针操作;
◼ int pthread_mutex_destroy(pthread_mutex_t *mutex);

        释放互斥量的资源;
◼ int pthread_mutex_lock(pthread_mutex_t *mutex);

        加锁,是阻塞状态,如果一个线程加锁了,其他线程就只能阻塞等待;
◼ int pthread_mutex_trylock(pthread_mutex_t *mutex);

        尝试加锁,如果加锁失败,不会阻塞,直接返回;
◼ int pthread_mutex_unlock(pthread_mutex_t *mutex);

        解锁。

        我们在前面的卖票程序中,出现的问题就是,三个线程抢占CPU资源,都进入临界区进行卖票,这就会出现一票多卖以及负票这种现象。为了解决这个问题,我们提出来加锁这种方法,就是在一个线程进入临界区时,加锁,不让别的线程进来,它卖,卖完后再解锁,允许其他线程进入。

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
//全局变量,所有的线程卖100张;
int tickets=100;
//创建一个互斥量
 pthread_mutex_t mutex;


void * sellticket(void * arg)
{
  //加锁  
    //卖票;
    while(1)
    {
         pthread_mutex_lock(&mutex);
        if(tickets>0)
            {        
                printf("%ld 正在卖第 %d 张票;\n",pthread_self(),tickets);
                tickets--;
            }
            else
            {
                pthread_mutex_unlock(&mutex);
                usleep(7000);
                break;
            }
            pthread_mutex_unlock(&mutex);
            usleep(7000);
    }   
    //解锁
    

    return NULL;
}
int main()
{
    //初始化互斥量
    pthread_mutex_init(&mutex,NULL);


    //创建三个子线程;
    pthread_t tid1,tid2,tid3;
    pthread_create(&tid1,NULL,sellticket,NULL);
    pthread_create(&tid2,NULL,sellticket,NULL);
    pthread_create(&tid3,NULL,sellticket,NULL);
    //回收子线程的资源,阻塞
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    pthread_join(tid3,NULL);
    //释放互斥量资源
     pthread_mutex_destroy(&mutex);
    pthread_exit(NULL);//退出主线程;

        return 0;
}

运行结果:

        交替卖票,三个线程交替完成卖票; 

void * sellticket(void * arg)

{

    while(1)

    {

         pthread_mutex_lock(&mutex);

        if(tickets>0)

            {        

                printf("%ld 正在卖第 %d 张票;\n",pthread_self(),tickets);

                tickets--;

            }

            else

            {

                pthread_mutex_unlock(&mutex);

                usleep(7000);

                break;

            }

            pthread_mutex_unlock(&mutex);

            usleep(7000);

    }

    return NULL;

}

注意:加锁和解锁的位置,以及加延时的位置,加延迟的作用是,防止一个线程抢占到CPU资源后,一直把票给卖完了,加上延时后,线程就算卖票,抢占上一个CPU资源,一次也卖不了太多的票。

三、死锁

        有时,一个线程需要同时访问两个或者更多不同的共享资源,而每个共享资源又都由不同的互斥量进行管理,当超过一个线程加锁同一组互斥量时,就有可能发生死锁。

        两个或者连个以上的进程执行过程中,因为争夺共享资源造成的一种互相等待的现象,若无外力作用,他们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁。

死锁的几种场景:

        忘记释放锁;

        重复加锁;

        多线程多锁,抢占锁资源;

 3.1忘记释放锁

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
//全局变量,所有的线程卖100张;
int tickets=100;
//创建一个互斥量
 pthread_mutex_t mutex;
void * sellticket(void * arg)
{
  //加锁  
    //卖票;
    while(1)
    {
         pthread_mutex_lock(&mutex);  
        if(tickets>0)
            {        
                printf("%ld 正在卖第 %d 张票;\n",pthread_self(),tickets);
                tickets--;
            }
            else
            {
                pthread_mutex_unlock(&mutex);
                usleep(7000);
                break;
            }
            usleep(7000);
    }   
    return NULL;
}
int main()
{
    //初始化互斥量
    pthread_mutex_init(&mutex,NULL);
    //创建三个子线程;
    pthread_t tid1,tid2,tid3;
    pthread_create(&tid1,NULL,sellticket,NULL);
    pthread_create(&tid2,NULL,sellticket,NULL);
    pthread_create(&tid3,NULL,sellticket,NULL);
    //回收子线程的资源,阻塞
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    pthread_join(tid3,NULL);
    //释放互斥量资源
    pthread_mutex_destroy(&mutex);
    pthread_exit(NULL);//退出主线程;
       return 0;
}

运行结果: 

         多线程抢占共享资源区,一个进程进入,加锁,出来,第二次无法进入以及其他进程也无法进入,造成死锁现象;

3.2重复加锁

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
//全局变量,所有的线程卖100张;
int tickets=100;
//创建一个互斥量
 pthread_mutex_t mutex;
void * sellticket(void * arg)
{
  //加锁  
    //卖票;
    while(1)
    {
         pthread_mutex_lock(&mutex);
         pthread_mutex_lock(&mutex);
        if(tickets>0)
            {        
                printf("%ld 正在卖第 %d 张票;\n",pthread_self(),tickets);
                tickets--;
            }
            else
            {
                pthread_mutex_unlock(&mutex);
                usleep(7000);
                break;
            }
            pthread_mutex_unlock(&mutex);
            pthread_mutex_unlock(&mutex);
            usleep(7000);
    }   
    return NULL;
}
int main()
{
    //初始化互斥量
    pthread_mutex_init(&mutex,NULL);
    //创建三个子线程;
    pthread_t tid1,tid2,tid3;
    pthread_create(&tid1,NULL,sellticket,NULL);
    pthread_create(&tid2,NULL,sellticket,NULL);
    pthread_create(&tid3,NULL,sellticket,NULL);
    //回收子线程的资源,阻塞
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    pthread_join(tid3,NULL);
    //释放互斥量资源
    pthread_mutex_destroy(&mutex);
    pthread_exit(NULL);//退出主线程;
       return 0;
}

运行结果: 

       多线程抢占共享资源区,一个进程进入,进入第一道锁,第二道锁无法进入因为已经这道锁已经被加过了,没能解锁,无法再加,造成死锁现象。 

3.3多线程多锁

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
//创建两个互斥量
pthread_mutex_t mutex1,mutex2;

void * workA(void *arg)
{
    
    pthread_mutex_lock(&mutex1);
    sleep(1);
    pthread_mutex_lock(&mutex2);
    printf("workA...\n");

    pthread_mutex_unlock(&mutex2);
    pthread_mutex_unlock(&mutex1);
  return NULL;

}

void * workB(void *arg)
{
    pthread_mutex_lock(&mutex2);
      sleep(1);
    pthread_mutex_lock(&mutex1);
    printf("workB...\n");

    pthread_mutex_unlock(&mutex1);
    pthread_mutex_unlock(&mutex2);

    return NULL;
}

运行结果: 

         线程A运行A区共享资源,线程B运行B区共享资源,两个区各有两把锁A区a锁将线程A锁住,B区b锁将线程B锁住,线程A在A区无法被B锁锁住,线程B无法在B区被A锁锁住,造成死锁。

四、读写锁

     问题:当有一个线程已经持有互斥锁时,互斥锁将所有试图进入临界区的线程都阻塞住。但是考虑一种情形,当前持有互斥锁的线程只是要读访问共享资源,而同时有其它几个线程也想读取这个共享资源,但是由于互斥锁的排它性,所有其它线程都无法获取锁,也就无法读访问共享资源了,但是实际上多个线程同时读访问共享资源并不会导致问题。   

     解决:在对数据的读写操作中,更多的是读操作,写操作较少,例如对数据库数据的读写应用。为了满足当前能够允许多个读出,但只允许一个写入的需求,线程提供了读写锁来实现。

读写锁的特点:

1、 如果有其它线程读数据,则允许其它线程执行读操作,但不允许写操作。
2、 如果有其它线程写数据,则其它线程都不允许读、写操作。
3、 写是独占的,写的优先级高。

◼ 读写锁的类型 pthread_rwlock_t
◼ int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
◼ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
◼ int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
◼ int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
◼ int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
◼ int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
◼ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

 案例; 

        创建8个线程,操作同一个全局变量。

        3个线程不定时写全局变量;

        5个线程不定时读全局变量。

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int num=1;
pthread_mutex_t mutex;
pthread_rwlock_t rwlock;
void * writenum(void * arg)
{

    while(1)
    {
        pthread_rwlock_wrlock(&rwlock);
        num++;
        printf("++write,tid:%ld,num:%d\n",pthread_self(),num);
        pthread_rwlock_unlock(&rwlock);
        usleep(100);
    }

    return NULL;

}
void * readnum(void * arg)
{
    while(1)
    {
        pthread_rwlock_rdlock(&rwlock);
        printf("===read,tid:%ld,num:%d\n",pthread_self(),num);
        pthread_rwlock_unlock(&rwlock);
         usleep(100);
    }
    return NULL;
}


int main()
{//创建3个写线程,5个读线程;
    pthread_t wtid[3],rtid[5];
    int i;
   // pthread_mutex_init(&mutex,NULL);
    pthread_rwlock_init(&rwlock,NULL);
    for(i=0;i<3;i++)
    {
        pthread_create(&wtid[i],NULL,writenum,NULL);
    }

    for(i=0;i<5;i++)
    {
        pthread_create(&rtid[i],NULL,readnum,NULL);
    }

    //设置线程分离
     for(i=0;i<3;i++)
    {
       pthread_detach(wtid[i]);
    }

    for(i=0;i<5;i++)
    {
        pthread_detach(rtid[i]);
    }

    pthread_rwlock_destroy(&rwlock);
    pthread_exit(NULL);
    return 0;
}

运行结果: 

        利用读写锁实现,写线程具有较高权限,读线程可以并行执行,不会发生阻塞,写线程会具有阻塞行为,整体效率要高效于互斥锁。 

五、生产者消费者模型

生产者消费者模型:

        模型含有三个对象:生产者、消费者以及容器;

        由生产者生产产品,消费者使用产品,且数量都是多个的,每个生产者与消费者用一个线程实现,那么容器中的产品就是数据。当容器满后生产者会阻塞等待消费者进行消费。当容器为空后,消费者会堵塞等待生产者生产。

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
struct Node
{
    int num;
    struct Node * next;
};
//头结点
struct Node* head=NULL;

void * producter(void * arg)
{
    //不断创建新的结点,添加在链表中;
    while(1)
    {
           struct Node * newNode =(struct Node *)malloc(sizeof(struct Node));
           newNode->next=head;
           head=newNode;
           newNode->num=rand()%1000;
           printf("add node,num:%d tid;%ld\n",newNode->num,pthread_self());
           usleep(100);
    }
    return NULL;
}

void * customer(void * arg)
{
    while(1)
    {
        //保存头结点的指针;
        struct Node* temp=head;
        head=head->next;
        printf("del node num:%d,tid:%ld\n",temp->num,pthread_self());
        free(temp);
        usleep(100);
    }
    return NULL;
}

int main()
{
    int i;
//创建5个生产者线程,和5个消费者线程;
    pthread_t ptids[5],ctids[5];
    for(i=0;i<5;i++)
    {
        pthread_create(&ptids[i],NULL,producter,NULL);
        pthread_create(&ctids[i],NULL,customer,NULL);
    }
    for(i=0;i<5;i++)
    {
        pthread_detach(ptids[i]);
        pthread_detach(ctids[i]);
    }
    while(1)
    {
    sleep(1);
    }
    pthread_exit(NULL);
    return 0;
}

运行结果:

        上述运行结果中,会出现段错误,出现的原因是多种的,首先我们在程序中没有考虑当 容器满后生产者会阻塞等待消费者进行消费。当容器为空后,消费者会堵塞等待生产者生产。这种情况就需要用到互斥锁、读写锁等操作。

六、条件变量

        问题:没有产品,消费者无法消费;

        解决:没有产品,消费者需要通知生产者去生产产品,当有了产品需要通知消费者进行消费。条件变量;

        条件变量不是锁,它的作用是当满足某些条件后,线程会发生阻塞;或者满足某些条件后,解除线程。它不能保证线程同步带来的数据安全性的问题,它是配合互斥锁来进行合作。

条件变量的类型 pthread_cond_t
◼ int pthread_cond_init(pthread_cond_t *restrict cond, const
pthread_condattr_t *restrict attr);
◼ int pthread_cond_destroy(pthread_cond_t *cond);
◼ int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
◼ int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex, const struct timespec *restrict
abstime);
◼ int pthread_cond_signal(pthread_cond_t *cond);
◼ int pthread_cond_broadcast(pthread_cond_t *cond)

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

//创建一个互斥量
pthread_mutex_t mutex;
//创建条件变量
pthread_cond_t cond;
struct Node
{
    int num;
    struct Node * next;
};
//头结点
struct Node* head=NULL;

void * producter(void * arg)
{
    //不断创建新的结点,添加在链表中;
    while(1)
    {
           pthread_mutex_lock(&mutex);
           struct Node * newNode =(struct Node *)malloc(sizeof(struct Node));
           newNode->next=head;
           head=newNode;
           newNode->num=rand()%1000;
           printf("add node,num:%d tid:%ld\n",newNode->num,pthread_self());
           //只要生产一个就通知消费者消费;
           pthread_cond_signal(&cond);
           pthread_mutex_unlock(&mutex);
           usleep(100);
    }
    return NULL;
}

void * customer(void * arg)
{
    while(1)
    {
        //保存头结点的指针;
        pthread_mutex_lock(&mutex);
        struct Node* temp=head;
        if(head!=NULL)
        {
            //有数据;
            head=head->next;
            printf("del node num:%d tid:%ld\n",temp->num,pthread_self());
            free(temp);
            pthread_mutex_unlock(&mutex);
            usleep(100);
        }else
        {
            //没有数据,需要等待
            //当这个函数调用阻塞时,会对互斥锁进行解锁,当不阻塞是时,继续向下执行会进行加锁。
            pthread_cond_wait(&cond,&mutex);
            pthread_mutex_unlock(&mutex);
        }
        
    }
    return NULL;
}

int main()
{
    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);
    int i;
//创建5个生产者线程,和5个消费者线程;
    pthread_t ptids[5],ctids[5];
    for(i=0;i<5;i++)
    {
        pthread_create(&ptids[i],NULL,producter,NULL);
        pthread_create(&ctids[i],NULL,customer,NULL);
    }
    for(i=0;i<5;i++)
    {
        pthread_detach(ptids[i]);
        pthread_detach(ctids[i]);
    }
    while(1)
    {
    sleep(1);
    }
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    pthread_exit(NULL);
    return 0;
}

 运行结果:

         加上互斥锁,作用在于线程同步时,共享资源区数据的安全性。

        加上条件变量,其意义在于当产品为0时,不使用条件变量,消费者处于无意义的缓冲,此时,只执行加锁和解锁,直到时间片用完才发生线程切换,浪费CPU资源。而加入条件变量,一旦发现缓冲区是空的,会立刻从运行态进入阻塞态,此时一定会发生线程切换,把CPU资源让出来。互斥锁和条件变量都可以实现线程同步,但是使用条件变量效率更高。

七、信号量

        信号量也称之为信号灯,它跟条件变量的作用是一致的,能起到阻塞线程的作用;灯亮表示资源可用,灯灭表示资源不可用。

◼ 信号量的类型 sem_t

◼ int sem_init(sem_t *sem, int pshared, unsigned int value);初始化;

    头文件: #include <semaphore.h>

         sem:信号量变量的地址;

         pshared为0:线程使用;非0:进程使用;

         value:信号量中的值;

◼ int sem_destroy(sem_t *sem);释放资源;

◼ int sem_wait(sem_t *sem);对信号量加锁,调用一次,对信号量的值减1,如果值为0就阻塞。

◼ int sem_trywait(sem_t *sem);尝试阻塞;

◼ int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);阻塞多久;

◼ int sem_post(sem_t *sem);对信号量解锁,调用一次,对信号量的值+1;

◼ int sem_getvalue(sem_t *sem, int *sval);  获取post的值;

利用信号量完成生产者消费者的模型:

sem_t psem;//创建一个生产者信号量

sem_t csem;//创建一个消费者信号量

init(psem,0,8);//初始化生产者信号量,其信号量的初值设置为8;

init(csem,0,0);//初始化消费者信号量,其信号量的初值设置为0;

producer()

{

    sem_wait(&psem);//对生产者信号量加锁,调用一次,对生产者信号量的值减1,如果值为0就阻塞。

    sem_pose(&csem);//调用一次,对消费信号量的值+1;

}

customer()

{

    sem_wait(&csem);对消费者信号量加锁,调用一次,对消费者信号量的值减1,如果值为0就阻塞。

    sem_pose(&psem);//调用一次,对生产者信号量的值+1;

}

 

    


#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
//创建一个互斥量
pthread_mutex_t mutex;
//创建两个信号量
sem_t psem,csem;

struct Node
{
    int num;
    struct Node * next;
};
//头结点
struct Node* head=NULL;

void * producter(void * arg)
{
    //不断创建新的结点,添加在链表中;
    while(1)
    {
           sem_wait(&psem);
           pthread_mutex_lock(&mutex);
           struct Node * newNode =(struct Node *)malloc(sizeof(struct Node));
           newNode->next=head;
           head=newNode;
           newNode->num=rand()%1000;
           printf("add node,num:%d tid:%ld\n",newNode->num,pthread_self());   
           pthread_mutex_unlock(&mutex);
           sem_post(&csem);
           usleep(100);
    }
    return NULL;
}

void * customer(void * arg)
{
    while(1)
    {
         sem_wait(&csem);
        //保存头结点的指针;
        pthread_mutex_lock(&mutex);
        struct Node* temp=head;
            //有数据;
            head=head->next;
            printf("del node num:%d tid:%ld\n",temp->num,pthread_self());
            free(temp);
            pthread_mutex_unlock(&mutex);
            sem_post(&psem);
    }
    return NULL;
}

int main()
{
    pthread_mutex_init(&mutex,NULL);
    sem_init(&psem,0,8);
    sem_init(&csem,0,0);
    int i;
//创建5个生产者线程,和5个消费者线程;
    pthread_t ptids[5],ctids[5];
    for(i=0;i<5;i++)
    {
        pthread_create(&ptids[i],NULL,producter,NULL);
        pthread_create(&ctids[i],NULL,customer,NULL);
    }
    for(i=0;i<5;i++)
    {
        pthread_detach(ptids[i]);
        pthread_detach(ctids[i]);
    }
    while(1)
    {
    sleep(1);
    }
    pthread_mutex_destroy(&mutex);

    pthread_exit(NULL);
    return 0;
}

    运行结果:

        本次我们讲述了线程的同步、互斥问题以及与互斥相关的死锁、读写锁以及举了相关案例——生产者消费者模型,并结合条件变量以及信息量完善了案例的实现。

        创做不易,感谢大家多多支持!!! 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值