线程同步与互斥:互斥锁、读写锁、POSIX无名信号量

同步与互斥:
  互斥是指两个线程不能同时运行,他们会相互排斥,必须等一个线程运行完,另一个才能运行;
  同步也是不能同时运行,但是他们必须按照一定的顺序执行。

一、线程
  线程的数据类型为:pthread_t

#include <pthread.h>

pthread_t pthread_self(void);   //获取线程id
int pthread_create( pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void *),void *arg );  //线程的创建
    /*pthread:线程id的地址
    * attr:线程参数,一般为NULL
    * start_routine:线程的入口函数
    * arg:函数的形参
    * 成功:0,  失败:非0
    */
int pthread_join(pthread_t thread, void **retval);  //回收线程资源,阻塞,成功:0,失败:非0
int pthread_detach(pthread_t thread);  //回收线程资源,非阻塞
    /*使线程和当前进程分离,分离后不代表线程不依赖于当前进程,线程分离的目的是将线程的回收工作交给系统*/
void pthread_exit(void *retval);   //线程退出

二、互斥锁
  线程里有一把锁–互斥锁,互斥锁是一种简单的加锁方式控制对共享资源的访问,互斥锁只有两种状态:加锁解锁

  互斥锁的操作流程:
    (1) 在访问共享资源临界区前,对互斥锁进行加锁
    (2) 在访问完释放互斥锁
    (3) 在堆互斥锁进行加锁之后,任何试图再次对互斥锁进行加锁的线程都将会被阻塞,直到锁被释放

  互斥锁的数据类型:pthread_mutex_t

1、原型

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
    /*初始化一个互斥锁,mutex:互斥锁地址,attr:互斥锁属性,一般为NULL
    *成功:0,成功申请的锁默认是打开的,   失败:-1
    */      
int pthread_mutex_lock(pthread_mutex_t *mutex);   //上锁,阻塞
int pthread_mutex_trylock(pthread_mutex_t *mutex); //上锁,非阻塞,若已经上锁,返回错误,即EBUSY
int pthread_mutex_unlock(pthread_mutex_t *mutex);   //解锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);   //销毁
/*利用互斥锁实现两个线程对打印程序的互斥访问*/
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t mutex;   //互斥锁

//打印程序
void printer(char *str)
{
    pthread_mutex_lock(&mutex);
    while (1)
    {
        putchar(*str);
        fflush(stdout);
        str++;
        sleep(1);
    }
    printf("\n");
    pthread_mutex_unlock(&mutex);
}

//线程1
void *pthread_func1(void *arg)
{
    char *str = "hello";
    printer(str); 
}

//线程2
void *pthread_func2(void *arg)
{
    char *str = "world";
    printer(str);
}

int main()
{
    pthread_t tid1, tid2;

    pthread_mutex_init(&mutex, NULL);  //初始化互斥锁

    pthread_create(&tid1, NULL, pthread_func1, NULL);
    pthread_create(&tid2, NULL, pthread_func2, NULL);

    pthread_mutex_destory(&mutex);   //销毁互斥锁
    return 0;
}

三、读写锁
  当一个线程已经持有互斥锁,互斥锁会将所有试图进入临界区的其他线程阻塞住。但是考虑这样一种场景:如果持有互斥锁的线程只是想读访问共享资源,其他的线程也只是想读访问共享资源,但是由于互斥锁的排他性,其他线程是没法获取到锁去访问共享资源的。

  为了解决上面的问题,线程提供了另一种机制:读写锁

  读写锁的规则如下:
   1) 如果某线程申请了读锁,其他线程可以再申请读锁,但不能申请写锁;
   2) 如果某线程申请了写锁,其他线程不能申请读锁,也不能申请写锁。

  POSIX定义的读写锁的数据类型为:pthread_rwlock_t

1、原型

#include <pthread.h>

int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr *attr);
    /*初始化rwlock所指向的读写锁
    *成功:0,读写锁的初始状态是解锁的     失败:-1
    */
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); //解锁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);  //销毁
/*读写锁实现4个线程的互斥读写,两个线程申请读锁读数据,两个线程申请写锁写数据*/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

int num = 1;    //全局共享数据
pthread_rwlock_t rwlock;

//pthread 1
void pthread_func1(void *arg)
{
    while (1)
    {
        pthread_rwlock_rdlock(&rwlock);
        printf("process 1 read num:%d.\n", num);
        pthread_rwlock_unlock(&rwlock);
        sleep(1);   
    }
}

//pthread 2
void pthread_func2(void *arg)
{
    while (1)
    {
        pthread_rwlock_rdlock(&rwlock);
        printf("process 2 read num:%d.\n", num);
        pthread_rwlock_unlock(&rwlock);
        sleep(2);   
    }
}

//process 3
void pthread_func3(void *arg)
{
    while (1)
    {
        pthread_rwlock_wrlock(&rwlock);
        num++;
        printf("After process 3 write num:%d.\n", num);
        pthread_rwlock_unlock(&rwlock);
        sleep(2);
    }
}

//process 4
void pthread_func4(void *arg)
{
    while (1)
    {
        pthread_rwlock_wrlock(&rwlock);
        num++;
        printf("After process 4 write num:%d.\n", num);
        pthread_rwlock_unlock(&rwlock);
        sleep(2);
    }
}

int main()
{
    pthread_t tid1, tid2, tid3, tid4;

    pthread_rwlock_init(&rwlock, NULL);    //初始化读写锁

    //创建线程
    pthread_create(&tid1, NULL, pthread_func1, NULL);
    pthread_create(&tid2, NULL, pthread_func2, NULL);
    pthread_create(&tid3, NULL, pthread_func3, NULL);
    pthread_create(&tid4, NULL, pthread_func4, NULL);

    //等待线程结束
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_join(tid3, NULL);
    pthread_join(tid4, NULL);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值