LINUX-线程的学习

1.什么是线程


     

轻量级的进程,可实现多任务的并发。
进程是操作系统资源分配的最小单位;
线程是操作系统任务调度的最小单位。


2. 线程的创建


     线程由某个进程创建。
     进程创建线程时,会为其分配独立的(8M)栈区空间;
     线程和所在进程,以及进程中的其他线程,共用进程的堆区、数据区、文本区。

3. 线程的调度


     宏观并行,微观串行     

4. 线程消亡


      1.  线程退出
      2. 回收线程资源空间

5. 进程和线程的区别
     


     进程:进程是操作系统资源分配的最小单位;
     资源消耗:进程资源开销大,每次创建都需要有0-4G的虚拟内存空间   
     效率角度:由操作系统创建,创建时耗时比线程大;跨进程调度比跨线程调度慢;
     通信方面: 进程间不能直接通信,需要使用进程间通信机制(IPC机制)
     安全性角度:进程安全性比线程高,各进程空间独立

     线程:线程是操作系统任务调度的最小单位。
     资源消耗:资源开销较小,只需要所在进程为其开辟8M的栈区空间
     效率角度:由所在进程创建;跨进程调度比跨线程调度慢;
     通信方面:通信简单,可以使用线程共享的区域进行通信(比如全局变量)
     安全性角度:线程没有进程安全性好,一个线程异常可能影响同一进程中的所有线程

6.线程的相关编程

     1. 线程的创建: pthread_create()
                                 pthread_self():获取当前线程的ID号
     2. 线程调度:由操作系统调度
     3. 线程消亡: 
           1. 线程退出:pthread_exit();        在线程任务函数中使用return结束线程
           2. 线程回收:pthread_join();


       #include <pthread.h>

       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
      功能:创建一个新的线程
      参数:
              thread : 保存线程ID的变量地址
              attr:线程属性的对象地址
                       NULL : 按照默认属性创建
             start_routine:函数的指针:指向线程启动后要执行的任务(线程任务函数)
             arg:为线程任务函数传递的参数
     返回值:
            成功:0
            失败:非0

        void pthread_exit(void *retval);

        功能:退出一个线程任务

        参数:retval:向回收线程传递的参数的地址

                   NULL:表示不传递参数

        int pthread_join(pthread_t thread, void **retval);

        功能:阻塞等待回收线程资源空间

        参数:thread:要回收的线程ID

                   retval:用来保存线程退出时传递的参数

        返回值:

                成功:0

                失败:-1

7.线程回收策略

线程回收策略:

        1.分离属性的线程:(没有空闲的线程可帮忙回收)pthread_detach()

        2.非分离属性线程:pthread_join()阻塞回收

1.分离属性:不需要被其他线程回收的线程称为分离属性得到线程,将来会被操作系统所回收

2.非分离属性:可以被其他线程回收,或者结束的线程,称为非分离属性的线程(默认属性:非分离属性)

8.线程间通信

全局变量通信:

临界资源:多个线程可以同时访问的资源称为临界资源。比如(全局变量、共享内存区域等)

资源竞争:多个线程在访问临界资源时,存在资源竞争。

互斥机制:多个线程访问临界资源时,具有排他性访问机制(一次只允许一个线程对该临界资源进行访问)

互斥锁:解决资源竞争问题

        实现步骤:

        1.创建互斥锁;pthread_mutex_t

        2.初始化互斥锁;pthread_mutex_init

        3.加锁;pthread_mutex_lock(pthread_mutex_t *mutex)

        4.解锁;pthread_mutex_unlock(pthread_mutex_t *mutex)

        5.销毁锁;pthread_mutex_destory(pthread_mutex_t *mutex)

init pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t restrict attr);

        功能:初始化锁

        参数:

                mutex:锁对象地址

                attr: 锁的属性(NULL:默认属性)

        返回值:

                成功:0

                失败:-1

线程间互斥锁防止资源竞争,以下代码实现:

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

int num = 10000;
pthread_mutex_t mutex;

void* thread_function1(void *arg) 
{
    pthread_mutex_lock(&mutex);
    int i = 0;
    for (i = 0; i < 100000; ++i) 
    {
        num += 1;
        printf("num = %d\n", num);
    }
    pthread_mutex_unlock(&mutex);
    return NULL;
}

void* thread_function2(void *arg) 
{
    pthread_mutex_lock(&mutex);
    int i = 0;
    for (i = 0; i < 100000; ++i) 
    {
        num += 1;
        printf("num = %d\n", num);
    }
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main()
{
    pthread_t thread1, thread2;
    pthread_mutex_init(&mutex, NULL);
    int ret1 = pthread_create(&thread1, NULL, thread_function1, NULL);
    if (ret1 != 0)
    {
        printf("pthread_create error\n");
        return -1;
    }
    int ret2 = pthread_create(&thread2, NULL, thread_function2, NULL);
    if (ret2 != 0)
    {
        printf("pthread_create error\n");
        return -1;
    }
    
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    pthread_mutex_destroy(&mutex);
    return 0;
}

9.线程间的同步机制

设计模式:

开闭原则:对增加开放,对修改关闭

异步:多线程、多进程本质是异步执行

线程间同步机制:让多个线程在执行摸个任务时,具有先后顺序的执行。

信号量:实现线程间同步。

操作步骤:

1.定义信号量对象:sem_t

2.初始化信号量:sem_init();

3.申请信号量:p操作:int sem_wait(sem_t *sem);

   释放信号量:v操作:int sem_post(sem_t *sem);

        PV操作

4.销毁信号量:int sem_destroy(sem_t *sem)

       头文件:#include <semaphore.h>

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

        功能:初始化信号量

        参数:

                sem: 要初始化的信号量对象地址

                pshared:

                        0:线程间共享

                        非0:进程间共享

                value: 信号量的初始值(初始资源数)

代码实现:

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

sem_t sem1;
sem_t sem2;
sem_t sem3;

void *fun1(void *arg)
{
    while(1)
    {
        sem_wait(&sem1); //等待信号量1变为0,然后执行后面的语句
        puts("A->");
        sem_post(&sem2); //信号量0变为1,然后执行后面的语句
        sleep(1);
    }
}

void *fun2(void *arg)
{
    while(1)
    {
        sem_wait(&sem2); //等待信号量2变为0,然后执行后面的语句
        puts("B->");
        sem_post(&sem3); //信号量0变为1,然后执行后面的语句
        sleep(1);
    }
}

void *fun3(void *arg)
{
    while(1)
    {
        sem_wait(&sem3);
        puts("C->");
        sem_post(&sem1);
        sleep(1);
    }
}

int main(int argc, char const *argv[])
{

    sem_init(&sem1, 0, 1);
    sem_init(&sem2, 0, 0);
    sem_init(&sem3, 0, 0);

    pthread_t tid1,tid2,tid3;
    pthread_create(&tid1, NULL, fun1, NULL);
    pthread_create(&tid2, NULL, fun2, NULL);
    pthread_create(&tid3, NULL, fun3, NULL);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    pthread_join(tid3, NULL);
    sem_destroy(&sem1);
    sem_destroy(&sem2);
    sem_destroy(&sem3);

    return 0;
}

互斥锁、信号量、读写锁、自旋锁  ------>锁

死锁:死锁指的是在多线程环境中,每个执行流(线程)都有未释放的资源,且互相请求对方未释放资源,从未导致陷入永久等待状态的情况。

现象:

现象1:忘记释放锁

现象2:重复加锁

现象3:多线程多锁,抢占资源不当

如:线程A获取了1锁,线程B获取了2锁,同时线程A还想获取2锁,线程B还想获取1锁

产生死锁的四个必要条件:

(1)互斥条件:一个资源每次只能被一个进程使用(一个执行流获取锁后,其他执行流不能再获取该锁)

(2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放(执行流本身用着一把锁并不释放,还在请求别的锁)

(3)不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺(A执行流拿着锁,其他执行流不能释放)

(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系(多个执行流拿着对方想要的锁,并且各执行流还去请求对方的锁)。

解决方法:

        1.锁一定要成对出现
        2.使线程的加锁顺序一致
        3.破坏环路等待条件
          使用非阻塞锁,一旦线程发现请求的锁被使用,就去释放自己拥有的锁
              pthread_mutex_trylock();
              int sem_trywait(sem_t *sem);

IPC机制:

1.管道

        有名管道:用于同一主机,任意进程间通信

        无名管道:只能用于同一主机,具有亲缘关系的进程间通信(父子进程间)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值