【Linux】线程、互斥锁、信号量sem

目录

一、线程

二、线程的创建

三、进程和线程的区别

四、线程调度

五、线程的消亡

六、线程相关的函数接口

1.线程的创建:

2.获得线程的tid

3.线程的退出的两种方法

4.线程空间的回收

P.S.函数指针数组

七、线程属性

八、线程间通信


一、线程

线程就是轻量级的进程,也是用来实现多任务的

是进程中的执行序列

进程---资源分配的基本单位

线程---调度执行的基本单位

线程的组成部分

私有资源:线程id、程序计数器、一组相关寄存器、栈

公共资源:多个线程共享的进程资源

二、线程的创建

线程由某个进程创建,从属于某个进程

内存:由某个进程分配独立的栈区空间(默认8M

        与其他线程和所在的进程公用数据区、堆区、文本区

        内核中存储线程控制块

三、进程VS线程

1.

进程--->程序的一次执行过程,CPU资源分配的最小单位

线程--->轻量级的进程,是进程中的执行单元,CPU调度的最小单位

2.资源消耗

进程资源消耗大,每次需要0-4G的虚拟内存空间

线程只需要所在进程分配8M的栈区空间

3.效率角度

线程的创建效率比进程

线程任务切换的效率高

多线程只需在同一进程空间内切换;多进程需要在不同的空间中切换

4.安全角度:多进程>多线程

各个进程之间空间独立,一个进程异常不会影响其余进程空间;一个线程异常结束会导致进程异常结束,进程异常结束,该进程内所有线程任务均无法向下执行

6.通信角度

线程间通信方便,进程间不能直接共享

线程共享全局变量,可以通过全局变量实现数据通信;进程空间是独立的,没有共享空间,通信实现比较复杂

四、线程调度

宏观并行,微观串行

五、线程的消亡

1.线程回收

2.线程资源回收

六、线程的函数接口

1.线程的创建

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

参数:

            thread:存放线程tid空间首地址
            attr:线程属性空间首地址

                        NULL:按照线程的默认属性去创建
            start_routine:回调函数线程要执行的函数的入口
            arg:给线程回调函数的参数

返回值:

             成功:0 
             失败:错误码errno

//判断出错
if(ret != 0)
{
    erron = ret;
    perror("create fail");
    return -1;
}
获得线程的tid
pthread_t pthread_self(void);

线程的退出
void pthread_exit(void *retval);
retval:线程退出的遗言
可以是数字,字符串

线程空间的回收
int pthread_join(pthread_t thread, void **retval);

 利用retval传给主线程遗言,传数字时,用局部变量无效

void * do_something(void *arg)
{
    static int status = 99;//局部变量在函数结束后会被销毁,
    printf("--%s---\n", __FUNCTION__);
    pthread_exit(&status);
    //pthread_exit("hello");//字符串在字符串常量区,全局有效
    //return "hello";
}

//在main函数中打印状态值
main
{
    ···
    void *retval;
    pthread_join(tid, &retval);
    // printf("retval = %d\n", *(int *)retval);
    printf("%s\n", (char *)retval);
}

 2.线程分离

int pthread_detach(pthread_t thread);
 功能:将线程设置成分离属性,系统自动回收该线程
 创建线程后就早点设置,防止线程都跑完了,还没设置  

七、函数指针数组

1.函数指针

一个指向函数的指针

2.函数指针的定义

函数:void fun(int a,int b);

函数指针:void (*pfun)(int a,int b);

3.函数指针的赋值

初始化:void (*pfun)(int a,int b) = fun; //int *p = &a;

赋值:void (*pfun)(int a,int b);

                pfun = fun; //int *p;  p = &a;

4.函数指针数组

把多个函数的地址存储再一个数组中

定义指针数组:char *arg[5];

函数指针数组:void (*arg[3])(int a,int b) = {fun1,fun2,fun3};

还可以通过typedef重命名函数指针类型:

typedef void(* pfun_array)(int a,int b);

将函数指针类型重命名为pfun_array

pfun_array arg[3] = {fun1,fun2,fun3};

5.指针函数

返回指针的函数

互斥锁

多个线程访问临界资源时,存在资源竞争,造成数据错乱.

临界资源(全局变量共享内存):多个线程可以同时操作的资源空间.

解决办法:多个线程访问临界资源时,进行排他性访问(同一时刻只允许一个线程对该临界资源进行访问)

功能:解决多线程访问临界资源时,存在资源竞争

如果只有一把锁,多个线程会竞争,谁抢到锁谁就先用

创建锁
pthread_mutex_t mutex;

初始化锁
/*
restrict mutex锁对象的地址
restrict attr锁的属性,一般传NULL
*/
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
                       const pthread_mutexattr_t *restrict attr);

上锁
int pthread_mutex_lock(pthread_mutex_t *mutex);

解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);

销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);

线程控制

异步:多任务各自执行各自的任务,互相之间没有直接干扰

同步:多个任务中的某些任务按照先后顺序执行

线程间同步:多个线程在某个任务执行过程中具有先后顺序

信号量

实现线程间同步(使用同步资源访问临界资源,可以达到互斥的效果)

定义信号量对象
sem_t sem;

初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
/*****
参数:
    sem:信号量对象地址
    pshared:    0线程间使用
                非0进程间使用
    value:初始化的资源数
返回值:成功0
      失败-1
*****/

申请信号量:P操作
int sem_wait(sem_t *sem);
/*
当申请的信号量资源数>0,sem_wait解除阻塞,表示申请到了该信号量,信号量资源数-1
当申请的信号量资源数=0,sem_wait阻塞等待信号量的释放
*/

释放信号量:V操作
int sem_post(sem_t *sem);
/*
该信号量的资源数自动+1
*/

销毁信号量
int sem_destroy(sem_t *sem);

信号的操作---主要就是来实现线程间的顺序

七、线程属性

对于创建线程的进程,无合适机会回收线程资源时,可以将线程设置成具有分离属性的线程。

线程属性:

线程的分离属性:线程结束时,不需要其他线程回收,会被操作系统自动回收。(类似孤儿进程)

线程的非分离属性:可以被其他线程回收(pthread_join)或结束。(僵尸进程)

设置线程的分离属性:

1.定义线程属性对象        pthread_attr_t attr;

2.初始化线程属性对象        

int pthread_attr_init(pthread_attr_t *attr);//用于初始化线程对象

3.设置线程的分离属性

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

参数:

        detachstate是int型的宏,设置线程的属性

4.以分离属性创建线程

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

5.销毁线程属性对象

int pthread_attr_destroy(pthread_attr_t *attr);

设置分离属性线程示例

    pthread_t tid;//定义线程tid
    pthread_attr_t attr;//定义线程属性对象
    pthread_attr_init(&attr);//初始化线程属性对象
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//设置分离属性
    pthread_create(&tid, &attr, task, NULL);//以分离属性创建线程

用非分离属性创建线程,系统资源不断被申请,却没有主动回收

用分离属性创建线程,线程执行结束后,就会被操作系统回收,重复利用空间

八、线程间通信

使用全局变量进行数据共享,临界资源容易导致资源竞争

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值