linux线程(用最简单的图解和文字告诉你什么是线程)【linux】(线程1)

我们在学习线程之前先说明C线程的操作和原理和我们C++和java都是类似的,所有线程的实现方式都是类似的,只不过所使用的语言不同。并且在C++和JAVA里面我们在创建新线程之后我们还需要启动线程,但是在C线程里面我们只要创建之后就会自动启动。

(必看)这篇博客会在开始的时候介绍线程,中间部分我们使用linux环境下面进行线程说明,然后在后面部分通过简单的语言再次理解线程,为我们后面阅读博客打好基础。

线程说明

线程:进程内部的一条执行路径|序列
进程:一个正在执行的程序(动态)(指令运行的过程)(执行路径)(执行序列)

主函数称为主线程
从主函数所在的执行序列中调用创建线程的方法创建一个线程,传递一个参数,参数就是线程函数,把创建的函数作为线程函数,相当于创建了第二条执行路径,即就是创建了一个新的线程。

调度及执行从线程的角度来看
资源分配从进程的角度来看

linux线程(用最简单的图解和文字告诉你什么是线程)【linux】(线程1)

linux平台创建线程

我们在C里面进行线程创建,其实是通过创建线程函数来实现的,也就是说创建一个线程我们直接看到的就是一个函数。
接下来我们写一下线程函数的代码:
linux线程(用最简单的图解和文字告诉你什么是线程)【linux】(线程1)

我们首先提出,创建线程的函数返回值和参数必须都是void * 类型
上面我们也是按照返回值和参数为 void * 来创建了一个函数,但是上面的函数目前并不是一个线程,只是一个普通的函数,我们可以正常的调用函数来执行函数体。

我们仍然可以像正常的C语言调用函数的方法调用pth_fun函数:
linux线程(用最简单的图解和文字告诉你什么是线程)【linux】(线程1)
执行结果为:
linux线程(用最简单的图解和文字告诉你什么是线程)【linux】(线程1)
那么如果我们要以线程的方式来运行,那么就必须把它改变为线程函数,那么如何把它改变为线程函数呢?
接下来我们进行解决
我们首先来看需要用到的用到的API

linux线程(用最简单的图解和文字告诉你什么是线程)【linux】(线程1)
那么我们来说明一下创建线程API的参数:
linux线程(用最简单的图解和文字告诉你什么是线程)【linux】(线程1)
那么我们在代码中就可以这样体现:
linux线程(用最简单的图解和文字告诉你什么是线程)【linux】(线程1)
这样我们就把pth_fun函数创建为一个线程。那么我们来运行看一下:
linux线程(用最简单的图解和文字告诉你什么是线程)【linux】(线程1)
这里我们可以看到出现了编译错误,但是没有提醒是那一行代码有问题,所以我们的代码书写是没有问题的,问题出现在哪里呢?

所以问题出现了链接的时候,在链接的时候需要去搜索库
程序在默认情况下gcc只会链接C语言的标准库,需要搜索其他库必须加入指定的库,否则不搜索。由于以前计算机运行比较慢,需要用到的库会直接告诉库的路径及文件名,所以情况下不会搜索所有的库文件,所以直到现在,我们只要使用的不是C语言的标准库,那么我们就要告诉编译器我们所用到的库。
所以需要连接pthraed 库才可以编译通过。
linux线程(用最简单的图解和文字告诉你什么是线程)【linux】(线程1)

上述情况下我们可以发现,当编译通过的时候,执行之后的结果就是程序直接退出了。现在又有问题,我们现在已经创建了线程,但是为什么创建的线程没有执行呢,我们上面讲到的通过个进程里面线程并发执行,但是现在的结果是我们只看到了程序直接结束了,我们下面进行说明。

程序里面现在有两个线程,main函数的主线程,还有在main函数里面创建的pth_fun子线程,主线程代表整个进程的存在,那么主线程return返回之后推出了,整个进程没有了,子线程也就结束了,所以主线程是不能退出了,那么子线程结束不会影响到主线程,但是主线程一旦结束整个进程就结束了子线程也就没有了。所以我们不能让主线程直接退出了,所以我们对于代码进行修改:
子线程不变,我们把主线程进行修改,不要让主线程结束退出:
linux线程(用最简单的图解和文字告诉你什么是线程)【linux】(线程1)
运行结果为:
linux线程(用最简单的图解和文字告诉你什么是线程)【linux】(线程1)
这样我们就可以看到了主线程mian和子线程pth_fun的并发执行过程。
那么在C++和JAVA里面我们在创建新线程之后我们还需要启动线程,但是在C线程里面我们只要创建之后就会自动启动。
在所有的语言里面子线程都是函数,只不过C++和JAVA会直接封装在类里面C里面的函数时直接暴露在外面的。

线程说明

为什么会有线程?

在上世纪60年代,也就是操作系统刚问世不久时,那个时候的OS只有进程没有线程,直到到了80年代才开始有了线程。
为什么有线程呢?
主要是人们开始发现,进程有缺点,为了弥补进程的缺点,就发明了线程这个东西,需要注意的是,这里我们说明的是弥补而不是替代,也就是说线程不会把进程给干掉,线程也是基于进程而实现的,是没办法干掉进程的。

进程的缺点
我们在前面的内容说过,为了让每个进程有一个安全的独立进程空间,OS使用了虚拟内存机制,通过虚拟内存机制,能够让每一个进程都有完全独立的进程空间。这种独立的进程空间最大的优点就是,可以很好地保证每一个进程的安全,不被其它进程所攻击或者干扰,
但是突出的优点往往又会导致另外的缺点。
拥有独立进程空间的进程有两大明显的缺点:
(1)进程间切换的计算机资源开销很大,切换效率非常低
(2)进程间数据共享的开销也很大,也就是说进程间数据通信的开销也会很大

我们下来说明第一个缺点:
1.进程间切换的计算机资源开销很大,切换效率非常低。

OS是通过虚拟内存机制来实现进程空间独立的,进程在并发运行时需要相互间的切换,即通过时间片切换,切换时必然需要涉及虚拟内存机制的控制,但是虚拟内存机制比较复杂,所以在进行进程间切换时,会耗费高昂的cpu、缓存(cache)、内存等计算机资源,也非常耗费切换时间。总之,进程切换的开销很大,需要清楚进程切换时的计算机资源开销是很大。

2.进程间数据共享的开销也很大。
当程序涉及多进程时,往往会涉及到进程间的通信,但是由于进程空间的独立性,OS提供了各种各样的通信机制,这些通信机制共同原理就是,通过OS来转发进程间的数据,但是调用OS提供的这些通信机制的函数时,这些OS函数的运行也是需要消耗相当cpu、内存等计算机资源的,同时也很耗费时间。因此,对于我们有OS的计算机来说,虽然进程是必不可少的,但是进程确又不能太多,进程太多会导致计算机资源被剧烈消耗,此时你会发现你的计算机非常的卡。

这一篇博客只是我们对于线程的认识和理解以及如何创建一个线程,这里只是创建,但是这一篇博客是后面线程学习的基础,需要读者认真仔细阅读,而且文字也比较容易理解,在读者理解进程和线程的关系的时候帮助也会比较大。