Linux系统编程:多线程(1)

目录

1.Linux线程的概念

1.1 什么是线程?

1.2 进程和线程的区别

1.3 线程的优缺点

2.线程控制

2.1 线程创建

2.1.1 函数介绍

2.1.2 多线程具体的实现 

2.1.3 线程的共享资源

2.1.3 线程ID

2.2 线程等待

2.3 线程终止

2.4 线程分离 

3.线程互斥 

3.1 进程线程间的互斥相关概念

3.2 互斥量

3.3 互斥量接口介绍

3.4 可重入和线程安全

3.4.1 概念

3.4.2 线程安全/不安全情况

3.4.3 可重入/不可重入情况

3.4.4 可重入与线程安全联系/区别

4.锁 

4.1 死锁的四个必要条件

4.2 避免死锁的方法


1.Linux线程的概念

1.1 什么是线程?

        线程就是进程内的一个执行流。进程相信大家都了解过了,那执行流又是什么呢?下面先简单回顾一下进程的概念,顺便引出线程的含义!

        在以前的学习中我们知道,进程=内核数据结构+进程对应的代码和数据。每个进程有自己的PCB(task_struct),虚拟地址空间(虚拟内存里面决定了进程能够看到的“资源”。),页表,还有所映射的物理地址。下图为一个进程的模型结构

进程模型结构

        如果我们把虚拟内存中的各个区域,页表都划分为若干个小区域,一部分供当前的进程使用。接着再创建几个"进程PCB",此时创建的“进程”不进行写时拷贝,不创建进程地址空间和页表。和task_struct指向同一个进程地址空间、页表,如下图所示。

        对这种情况该如何解释呢?对只创建PCB,从当前的进程分配资源的执行流就叫做线程。因为我们可以通过虚拟地址空间+页表对进程进行资源划分,单个"进程"执行粒度,一定要比之前的进程要细。线程再进程的地址空间内运行,拥有该进程的一部分资源。通俗一点讲就是进程内的所有线程组成了一个进程。线程负责进程的部分代码。

        经过上面的叙述,那么我们可以重新叙述进程,就是多个PCB,一个进程地址空间,多级页表,所映射对应的物理内存。这里的每个PCB可以称之为轻量级进程。那么我们之前讲的进程是什么呢?其实它是包含一个线程的进程。

1.2 进程和线程的区别

从上面看,进程和线程是紧密相关联的,那么他俩的区别又是什么呢?

进程

线程

承担分配系统资源的基本实体

        (用来整体申请资源)

CPU调度的基本单位

(向进程要资源)

进程具有独立性 线程的大部分资源是共享的
代码数据和数据结构的总和 只占有进程部分的资源

得出几点结论:

  •  Linux内核中没有真正意义的线程,使用进程PCB来模拟线程的
  • 站在CPU的视角,每一个PCB,都可以称之为轻量级进程
  • Linux线程是CPU调度的基本单位,进程是承担分配系统资源的基本单位
  • 进程使用来整体申请资源的,线程向进程要资源
  • Linux无法直接提供创建线程的系统调用接口,只能提供创建轻量级进程的接口。

1.3 线程的优缺点

优点 缺点
创建线程比创建进程代价小 健壮性/鲁棒性较差
线程切换比进程切换要简单的多 编写与调试难度提高
线程占用的资源较少

缺乏访问控制

可以并行运行
计算密集型应用,I/O密集型应用

2.线程控制

2.1 线程创建

2.1.1 函数介绍

#include <pthread.h>

int pthread_create(pthrea_t* thread, const pthread_att_t* attr, void*(*start_routine)(void*), void* arg);

参数:

  • pthread_t* thread:相当于无符号的整型,这里暂且称之为线程id
  • const pthread_att_t* attr:设置线程的属性,当前先设置为nullptr
  • void*(*start_routine)(void*):函数指针,线程将要执行的该函数
  • void* arg:将传入上面函数的参数

返回值:成功返回0,失败返回错误码。

使用此方法必须链接libpthread-2.17.so原生线程库。任何Linux都必须默认携带改库。编译时加

-lpthread选项。

命令行查看线程的命令:ps -aL

PID和LWP相同的为主线程,不同的为新线程。CPU调度时,是以LWP为标识符表示特定一个执行流的。

2.1.2 多线程具体的实现 

代码1:

#include <iostream>
#include <cassert>
#include <cstdio>
#include <pthread.h>
#include <unistd.h>

using namespace std;

void func();



// 新线程
void *thread_routine(void *args)
{
    const char *name = (const char*)args;
    while(1)
    {
        cout << "我是新线程, 名字为:" << name << ":";
        
        fflush(stdout);
        sleep(1);
    }
}

int main()
{
    pthread_t tid;
    int n = pthread_create(&tid, nullptr, thread_routine, (void*)"thread one");
    assert(n == 0);
    (void)n;

    while(1)
    {
        char tidbuffer[64];
        snprintf(tidbuffer, sizeof(tidbuffer), "0x%x", tid);
        
        cout << "我是主线程,我创建出来的线程id为:" << tidbuffer << ":" ;
        
        fflush(stdout);
        sleep(1);
    }

    return 0;
}

结果: 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值