Linux线程的基本概念和使用、分离

线程概念

线程是指运行中的程序的调度单位。一个线程指的是进程中一个单一顺序的控制流,也被称为轻量级线程。它是系统独立调度和分配的基本单位。同一进程中的多个线程将共享该系统中的全部系统资源,比如文件描述符和信号处理等。一个进程可以有很多线程,每个线程并行执行不同的任务。(线程是并发的,没有谁运行先,谁运行后)

线程与进程比较

① 和进程相比,它是一种非常“节俭”的多任务操作方式。在Linux系统中,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护其代码段、堆栈段和数据段,这种多任务工作方式的代价非常“昂贵”。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且线程间彼此切换所需要时间也远远小于进程间切换所需要的时间。

② 线程间方便的通信机制。对不同进程来说它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行。这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其他线程所用,不仅方便,而且快捷。

线程基本编程(线程的函数基本都是返回0表示成功)

Linux系统下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。因为pthread的库不是Linux系统的库,所以在编译时要加上 -lpthread。例如:gcc filename -lpthread。注意,这里要讲的线程相关操作都是用户空间中的线程的操作。

线程创建:创建线程实际上就是确定调用该线程函数的入口点,这里通常使用的函数是pthread_create()。在线程创建后,就开始运行相关的线程函数。
在这里插入图片描述
线程退出:在线程创建后,就开始运行相关的线程函数,在该函数运行完之后,该线程也就退出了,这也是线程退出的一种方法。另一种退出线程的方法是使用函数pthread_exit(),这是线程的主动行为。这里要注意的是,在使用线程函数时,不能随意使用exit()退出函数来进行出错处理。由于exit()的作用是使调用进程终止,而一个进程往往包含多个线程,因此,在使用exit()之后,该进程中的所有线程都终止了。在线程中就可以使用pthread_exit()来代替进程中的exit()。
在这里插入图片描述
线程等待:由于一个进程中的多个线程是共享数据段的,因此,通常在线程退出后,退出线程所占用的资源并不会随着线程的终止而得到释放。正如进程之间可以用wait()系统调用来同步终止并释放资源一样,线程之间也有类似机制,那就是pthread_join()函数。pthread_join()用于将当前进程挂起来等待线程的结束。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源就被收回。
在这里插入图片描述
线程取消:前面已经提到线程调用pthread_exit()函数主动终止自身线程,但是在很多线程应用中,经常会遇到在别的线程中要终止另一个线程的问题,此时调用pthread_cancel()函数来实现这种功能,但在被取消的线程的内部需要调用pthread_setcancel()函数和pthread_setcanceltype()函数设置自己的取消状态。例如,被取消的线程接收到另一个线程的取消请求之后,是接受函数忽略这个请求;如果是接受,则再判断立刻采取终止操作还是等待某个函数的调用等。
在这里插入图片描述
线程标识符获取:获取调用线程的标识ID。
在这里插入图片描述
线程清除:线程终止有两种情况:正常终止和非正常终止。线程主动调用pthread_exit()或者从线程函数中return都将使线程正常退出,这是可预见的退出方式;非正常终止是线程在其它线程的干预下,或者由于自身运行出错(比如访问非法地址)而退出,这种退出方式是不可预见的。不论是可预见的线程终止还是异常终止,都回存在资源释放的问题,如何保证线程终止时能顺利地释放掉自己所占用的资源,是一个必须考虑的问题。

从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作(包括调用pthread_exit()和异常终止,不包括return)都将执行pthread_cleanup_push()所指定的清理函数。

在这里插入图片描述
在这里插入图片描述
实验1

功能:使用pthread_create()函数创建线程的实例

代码:thread_create.c文件
在这里插入图片描述
在这里插入图片描述
编译:使用命令:gcc thread_create.c -o thread_create -lpthread编译,注意不要忘了加 -lpthread(链接线程的库),否则会报错。

执行:
在这里插入图片描述
实验2

功能:使用pthread_exit()函数退出线程的举例

代码:thread_exit.c文件
在这里插入图片描述
编译:gcc thread_exit.c -o thread_exit -lpthread

执行:./thread_exit
在这里插入图片描述
实验3

功能:用pthread_join()实现线程等待。

代码:thread_join.c文件
在这里插入图片描述
编译:gcc thread_join.c -o thread_join -lpthread

执行:./thread_join
在这里插入图片描述
可以看出,pthread_join()等到线程结束后,程序才继续执行。

实验4

功能:使用pthread_self()获取线程ID

代码:thread_id.c文件
在这里插入图片描述
编译:gcc thread_id.c -o thread_id -lpthread

执行:./thread_id
在这里插入图片描述
实验5

功能:线程清理函数的使用

代码:thread_clean.c
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意,在编写的代码的时候,自己修改一下传递的参数和clean_pop函数的参数,相信你会更有收获。

编译:gcc thread_clean.c -o thread_clean -lpthread

执行:./thread_clean
在这里插入图片描述
实验6

功能:本实验创建了3个进程,为了更好的描述线程之间的并行执行,让3个线程共用同一个执行函数。每个线程都有5次循环(可以看成5个小任务),每次循环之间会随机等待1~10s的时间,意义在于模拟每个任务的到达时间是随机的,并没有任何特定的规律。

代码:thread.c文件,该代码文件点此下载
在这里插入图片描述
在这里插入图片描述
编译:gcc thread.c -o thread -lpthread

执行:./thread
在这里插入图片描述
从实验结果可以看出,线程执行的顺序杂乱无章的,看着就头疼,下一节就利用线程之间的同步与互斥机制处理此文件http://blog.csdn.net/mybelief321/article/details/9390707

linux下线程的分离和结合属性

在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。

默认情况下,线程被创建成可结合的。为了避免存储器泄漏,每个可结合线程都应该要么被显示地回收,即调用pthread_join;要么通过调用pthread_detach函数被分离。如果一个可结合线程结束运⾏行但没有被join,则它的状态类似于进程中的Zombie Process, 即还有一部分资源没有被回收,所以创建线程者应该调用pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源。 由于调用pthread_join后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此。例如,在Web服务器中当主线程为每个新来的连接请求创建一个子线程进 行处理的时候,主线程并不希望因为调用pthread_join而阻塞(因为还要继续处理之后到来 的连接请求), 这时可以在子线程中加入代码:

pthread_detach(pthread_self())

或者父线程调用时加入:

pthread_detach(thread_id)

这将该子线程的状态设置为分离的(detached),如此一来,该线程运⾏行结束后会自动释 放所有资源。
代码示例:

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>

void* pthread_running(void *_val)
{ 
    pthread_detach(pthread_self());
    printf("%s\n", (char*)_val);
    return NULL;
}

int main()
{ 
    pthread_t tid;
    int ret = pthread_create(&tid, NULL, pthread_running, "main thread is running");

    if(ret != 0)
    { 
        printf("create thread error! info is:%s\n", strerror(ret));
        return ret;
    }

    int temp = 0;
    sleep(1);
    if(0 == pthread_join(tid, NULL))
    { 
        printf("pthread wait success!\n");
        temp = 0;
    }
    else
    { 
        printf("pthread wait failed!\n");
        temp = 1;
    }

    return temp;
}

运行结果:
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值