IO--线程的同步与互斥

目录

线程概念

1.定义

2.进程和线程区别

3.函数接口

创建线程

结束线程

回收线程

线程分离

获取线程

练习

运行结果:

线程同步

1.概念 

2.同步机制

3.特性

4.函数接口

线程互斥

1.概念

2.函数接口

练习

运行结果

 3.死锁


线程概念

1.定义

是一个轻量级的进程,为了提高系统的性能引入线程

线程和进程都参与统一的调度。

在同一个进程中创建的线程共享该进程的地址空间。

2.进程和线程区别

共性:都为操作系统提供了并发执行能力

不同点:调度和资源:线程是系统调度的最小单位,进程是资源分配的最小单位

               地址空间方面:同一个进程创建的多个线程共享进程的资源;进程的地址空间相互独立

               通信方面:线程通信相对简单,只需要通过全局变量可以实现,但是需要考虑临界资源访问的问题;进程通信比较复杂,需要借助进程间的通信机制(借助3g-4g内核空间)

               安全性方面:线程安全性差一些,当进程结束时会导致所有线程退出;进程相对安

3.函数接口

创建线程

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,

void *(*start_routine) (void *), void *arg);

参数:thread:线程ID

attr:线程属性,一般设为NULL

start_routine:函数指针,传递函数名,

函数定义void *fun(void *arg){}

arg:给前面的函数传参

返回值:成功:0

失败:错误码

结束线程

int pthread_exit(void *value_ptr)

功能:用于退出线程的执行

参数:value_ptr:线程退出时返回的值

返回值:成功 : 0

失败:errno

回收线程

int pthread_join(pthread_t thread, void **value_ptr)

功能:用于等待一个指定的线程结束,阻塞函数

参数:thread:创建的线程对象

value_ptr:指针*value_ptr指向线程返回的参数

返回值:成功 : 0

失败:errno

线程分离

int pthread_detach(pthread_t thead)

功能:让线程分离,线程结束时自动回收线程资源

参数:thead:线程ID

获取线程

pthread_t pthread_self(void)

功能:获取当前线程的ID

返回值:获取的线程ID

练习

主线程循环从终端输入字符串,子线程循环打印主线程输入的字符串,当输入"quit"结束程序

#include<stdio.h>
#include<string.h>
#include<pthread.h>
char buf[32]="";
int flag=0;    //标志位 置0
void *headler(void *arg)
{
    while(1)
    {
        if(flag==1){
            if(!strcmp(buf,"quit"))
               break;
            printf("buf:%s\n",buf);
            flag=0;
        }
    }
}
int main(int argc, char const *argv[]) 
{
    pthread_t tid; //线程ID
     //创建线程
    if(pthread_create(&tid,NULL,headler,buf)!=0)
    {
        printf("create thread err");
        return -1;
    }
    while(1)
    {
        scanf("%s",buf);//主线程循环输入
        flag=1;
        if(!strcmp(buf,"quit"))//当输入quit时退出
           break;
    }
    pthread_join(tid,NULL);//回收线程
    return 0;
}

运行结果:

线程同步

1.概念 

同步(synchronization)指的是多个任务(线程)按照约定的顺序相互配合完成一件事情

2.同步机制

通过信号量实现线程间同步

信号量:由信号量来决定线程是继续运行还是阻塞等待,信号量代表某一类资源,其值表示系统中该资源的数量

信号量是一个受保护的变量,只能通过三种操作来访问:初始化、操作(申请资源)、操作(释放资源)

信号量的值为非负整数

3.特性

P操作:

当信号量的值大于0时,可以申请到资源,申请资源后信号量的值减1

当信号量的值等于0时,申请不到资源,函数阻塞

V操作:不阻塞,执行到释放操作,信号量的值加1

4.函数接口

int sem_init(sem_t *sem, int pshared, unsigned int value)

功能:初始化信号量

参数:sem:初始化的信号量对象

pshared:信号量共享的范围(0: 线程间使用 非0:1进程间使用)

value:信号量初值

返回值:成功 0

失败 -1

int sem_wait(sem_t *sem)

功能:申请资源 P操作

参数:sem:信号量对象

返回值:成功 0

失败 -1

注:此函数执行过程,当信号量的值大于0时,表示有资源可以用,则继续执行,同时对信号量减1;当信号量的值等于0时,表示没有资源可以使用,函数阻塞

int sem_post(sem_t *sem)

功能:释放资源 V操作

参数:sem:信号量对象

返回值:成功 0

失败 -1

注:释放一次信号量的值加1,函数不阻塞

线程互斥

1.概念

临界资源:一次仅允许一个进程/线程所使用的资源

临界区:指的是一个访问共享资源的程序片段

互斥:多个线程在访问临界资源时,同一时间只能一个线程访问

互斥锁:通过互斥锁可以实现互斥机制,主要用来保护临界资源,每个临界资源都由一个互斥锁来保护,线程必须先获得互斥锁才能访问临界资源,访问完资源后释放该锁。如果无法获得锁,线程会阻塞直到获得锁为止。

2.函数接口

int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)

功能:初始化互斥锁

参数:mutex:互斥锁

attr: 互斥锁属性 // NULL表示缺省属性

返回值:成功 0

失败 -1

int pthread_mutex_lock(pthread_mutex_t *mutex)

功能:申请互斥锁

参数:mutex:互斥锁

返回值:成功 0

失败 -1

注:和pthread_mutex_trylock区别:pthread_mutex_lock是阻塞的;pthread_mutex_trylock不阻塞,如果申请不到锁会立刻返回

int pthread_mutex_unlock(pthread_mutex_t *mutex)

功能:释放互斥锁

参数:mutex:互斥锁

返回值:成功 0

失败 -1

int pthread_mutex_destroy(pthread_mutex_t *mutex)

功能:销毁互斥锁

参数:mutex:互斥锁

练习

案例:两个线程,定义全局数组,一个线程循环打印数组数据,另一个线程循环倒置

int a[10] = {0,1,2,3,4,5,6,7,8,9};

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

int a[10]={0,1,2,3,4,5,6,7,8,9};
pthread_mutex_t lock;
void *swap_handler(void *arg)//循环打印数组
{
  int i;
  while(1)
  {   
      //上锁
      pthread_mutex_lock(&lock);
      for(i=0;i<10;i++)
          printf("%d",a[i]);
      printf("\n");
      //解锁
      pthread_mutex_unlock(&lock);
      sleep(1);
  }
}
void *reswap_handler(void *arg)//循环打印倒置数组
{
   int i,t;
  while(1)
  {
       //上锁
      pthread_mutex_lock(&lock);
      for(i=0;i<5;i++){
          t=a[i];
          a[i]=a[9-i];
          a[9-i]=t;
      }
      //解锁
      pthread_mutex_unlock(&lock);
  }
}
int main(int argc, char const *argv[])
{
    pthread_t t1,t2;
    pthread_create(&t1,NULL,swap_handler,NULL);
    pthread_create(&t2,NULL,reswap_handler,NULL);
    if(pthread_mutex_init(&lock,NULL)!=0)
    {
        printf("lock err");
        return -1;
    }
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);
    return 0;
}

运行结果

 3.死锁

是指两个或两个以上的进程/线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去

死锁产生的四个必要条件

1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用

2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。

3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。

4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。

注意:当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值