操作系统—线程(2)线程控制—互斥与同步

一.线程控制:互斥

  • 互斥概念:互斥是多线程中对临界资源的排他性访问;互斥机制通过互斥锁来保证临界资源的访问控制。
  • 框架
    1. 定义互斥锁pthread_mutex_t mutex;
    2. 初始化锁:int pthread_mutex_init(
                                        pthread_mutex_t *mutex,
                                        const pthread_mutexattr_t *attr);
                        功能:将已经定义好的互斥锁初始化。
                        参数:mutex-要初始化的互斥锁。
                                   attr-初始化的值,一般是NULL表示默认锁。
                        返回值:成功为0,失败为非0。
    3. 加锁:int pthread_mutex_lock(pthread_mutex_t *mutex);
                        功能:用指定的互斥锁开始加锁代码。
                                   加锁后的代码到解锁部分的代码属于原子操作,
                                   在加锁期间其他进线程都不能操作该部分代码。
                                   如果该函数执行时mutex已被其他部分使用,则代码阻塞。
                        参数:mutex-用来给代码加锁的互斥锁。
                        返回值:成功为0,失败为非0。
    4. 解锁:int pthread_mutex_unlock(pthread_mutex_t *mutex);
                        功能:将指定的互斥锁解锁。
                                   解锁之后代码不再排他访问,一般加锁解锁同时出现。
                        参数:mutex-用来解锁的互斥锁。
                        返回值:成功为0,失败为非0。
    5. 销毁:int pthread_mutex_destroy(pthread_mutex_t *mutex);
                        功能:使用互斥锁完毕后需要销毁互斥锁。
                        参数:mutex-用来销毁的互斥锁。
                        返回值:成功为0,失败为非0。
    6. 尝试加锁:int pthread_mutex_trylock(pthread_mutex_t *mutex);
                        功能:类似加锁函数效果,唯一区别就是不阻塞。
                        参数:mutex-用来加锁的互斥锁。
                        返回值:成功为0,失败为非0。

二.线程控制:同步

  • 同步概念:同步是有一定先后顺序的对资源的排他性访问,互斥锁相比虽同样可以控制排他性访问,但没有次序。
  • 框架
    1. 定义信号量:pthread_mutex_t mutex;
    2. 初始化信号量:int sem_init(sem_t *sem, int pshared, unsigned int value);
                        功能:将已经定义好的信号量赋值。
                        参数:sem-要初始化的信号量
                                   pshared = 0 ;表示线程间使用信号量
                                                 !=0 ;表示进程间使用信号量
                                   value-信号量的初始值,一般无名信号量都是二值信号量-> 
                                                 0 表示红灯,进程暂停阻塞
                                                 1 表示绿灯,进程可以通过执行
                        返回值:成功为0,失败为-1。
    3. 资源申请:int sem_wait(sem_t *sem);
                        功能:如果sem有资源(==1),则申请该资源,程序继续运行
                                   如果sem没有资源(==0),则线程阻塞等待,一旦有资源
                                                 则自动申请资源并继续运行程序。
                                   注意:sem 申请资源后会自动执行 sem = sem - 1。
                        参数:sem-要判断的信号量。
                        返回值:成功为0,失败为-1。
    4. 资源释放:int sem_post(sem_t *sem);
                        功能:函数可以将指定的sem信号量资源释放并默认执行,
                                                 sem = sem+1;
                                   线程在该函数上不会阻塞。
                        参数:sem-要释放资源的信号量。
                        返回值:成功为0,失败为-1。
    5. 销毁信号量: int sem_destroy(sem_t *sem);
                        功能:使用完毕将指定的信号量销毁。
                        参数:sem-要销毁的信号量。
                        返回值:成功为0,失败为-1。

三.死锁生成

1.死锁生成主要原因

  • 系统资源不足:当可用资源少于进程需求时,进程可能会因为等待资源而无法继续执行。
  • 进程运行推进的顺序不合适:进程请求和释放资源的顺序如果不合理,可能导致循环等待。
  • 资源分配不当:不合理的资源分配策略可能导致资源无法有效利用,增加了死锁的风险。

2.死锁生成必要条件

  • 互斥条件:每个资源在一段时间内只能由一个进程占有,其他请求该资源的进程必须等待。
  • 请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而这个请求的资源正被其他进程占有,因此请求进程会被阻塞,但它对已获得的资源不释放。
  • 不剥夺条件:进程已获得的资源,在未使用完之前,不能被其他进程强行夺走,只能由进程自愿释放。
  • 循环等待条件:存在一种进程资源的循环等待关系,即进程间形成一种头尾相接的循环链,每个进程都在等待下一个进程所占有的资源。

四.线程控制代码示例

示例:用多线程程序设计一个火车票售票系统,
        要求至少有两个售票窗口,每个售票窗口
        不能重复买票,将100张车票均匀的从两个
        窗口卖出即可。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
int num=100;
int WIN[2]={1,1};
sem_t sem_WIN;
pthread_mutex_t mutex;
pthread_mutex_t mutex_win;
int get_win()
{

    sem_wait(&sem_WIN);
    int i = 0 ;
    for(i = 0 ;i<2;i++)
    {
        pthread_mutex_lock(&mutex_win);
        if(1==WIN[i])
        {
            WIN[i] = 0 ;
            pthread_mutex_unlock(&mutex_win);

            return i;
        }else 
        {
            pthread_mutex_unlock(&mutex_win);
        }
    }

    return -1;

}
void relese_win(int id)
{
    pthread_mutex_lock(&mutex_win);
    WIN[id]=1;
    pthread_mutex_unlock(&mutex_win);
    sem_post(&sem_WIN);
}
void* th(void* arg)
{

    while(1)
    {
        pthread_mutex_lock(&mutex);
        if(num>0)
        {
            int n = num--;
            pthread_mutex_unlock(&mutex);
            int id = get_win();
            printf("win %d, ticket:%d tid:%lu\n",id+1 ,n,pthread_self());
            usleep(1000*100);
            relese_win(id);
        }else
        {
            pthread_mutex_unlock(&mutex);
            break;
        }

    }
    return NULL;

}
int main(int argc, char *argv[])
{
    pthread_t tid1,tid2;
    pthread_mutex_init(&mutex,NULL);
    pthread_mutex_init(&mutex_win,NULL);
    sem_init(&sem_WIN,0,2);
    pthread_create(&tid1,NULL,th,NULL);
    pthread_create(&tid2,NULL,th,NULL);
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    sem_destroy(&sem_WIN);
    pthread_mutex_destroy(&mutex);
    pthread_mutex_destroy(&mutex_win);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值