• 为了保证你在浏览本网站时有着更好的体验,建议使用类似Chrome、Firefox之类的浏览器~~
    • 如果你喜欢本站的内容何不Ctrl+D收藏一下呢,与大家一起分享各种编程知识~
    • 本网站研究机器学习、计算机视觉、模式识别~当然不局限于此,生命在于折腾,何不年轻时多折腾一下

从零学习linux多线程编程_第一篇

Linux admin 5年前 (2015-05-30) 1716次浏览 0个评论 扫描二维码

概念–线程

线程(thread)技术早在 60 年代就被提出,但真正应用多线程到 os 中去,是在 80 年代中期,solaris 是这方面的佼佼者。传统的 Unix 也支持线程的概念,但是在一个进程(process)中只允许有一个线程,这样多线程就意味着多进程。现在,多线程技术已经被许多 os 所支持,包括 Windows/NT,当然,也包括 Linux。

为什么有了进程的概念后,还要再引入线程呢?使用多线程到底有哪些好处?什么的系统应该选用多线程?我们首先必须回答这些问题。
使用多线程的理由之一是和进程相比,它是一种非常”节俭”的多任务 方式。我们知道,在 Linux 系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种”昂贵”的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的 30 倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。
使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为 static 的数据更有可能给多线程程序带来灾难 ***的打击,这些正是编写多线程程序时最需要注意的地方。

除了以上所说的优点外,不和进程比较,多线程程序作为一种多任务、并发的工作方式,当然有以下的优点:

1. 提高应用程序响应。这对图形界面的程序尤其有意义,当一个 程序 运行耗时很长时,整个系统都会等待这,此时程序不会响应键盘、鼠标、菜单的 *** 作,而使用多线程技术,将耗时长的 线程(time consuming)置于一个新的线程,可以避免这种尴尬的情况。

2. 使多 CPU 系统更加有效。os 会保证当线程数不大于 CPU 数目时,不同的线程运行于不同的 CPU 上。

3. 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。

线程相关函数分析

对于初学 Linux 多线程的人来说理解多线程编程还是有点难度的,起码我是这个样子。从一开始看书学写多线程看着别人的代码很多时候似乎看懂实际上都没有完全理解多线程的精髓。现在把自己所知道的整理下供大家交流。

线程创建

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

第一个参数是指向 pthread_t 结构的指针在头文件 pthread_t 定义如下:

typedef unsigned long int pthread_t;

第二个参数是指向 pthread_attr_t 的指针此结构在头文件中定义如下:

typedef union { char __size[__SIZEOF_PTHREAD_ATTR_T]; long int __align; } pthread_attr_t;

第三个参数是一个 void 类型指针,由于 void 类型可以作为很多类型指针的转换对象,这里是针对线程函数对象,也就是函数指针将会转换成 void 类型指针
第四个##参数是线程函数传递的参数,由于也是 void 类型所以可以传递多种类型。
线程如果成功创建则返回 0 失败则返回错误代码
,不会返回-1,与 pthread 相关的函数都是这样!谨记

线程退出

(1)执行完成后隐式退出;

(2)由线程本身显示调用 pthread_exit 函数退出;

pthread_exit (void * retval) ;

(3)被其他线程用 pthread_cance 函数终止:

pthread_cancel(pthread_t thread) ;

在某线程中调用此函数,可以终止由参数 thread 指定的线程。
如果一个线程要等待另一个线程的终止,可以使用 pthread_join 函数,该函数的作用是调用 pthread_join 的线程将被挂起直到线程 ID 为参数 thread 的线程终止:

pthread_join (pthread_t thread, void** threadreturn);

下面给出一个例子详细介绍多线程执行过程:

#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
static void thread_one(char* msg);
static void thread_two(char* msg);
int  main(int argc, char** argv)
{
pthread_t th_one,th_two;
char * msg="thread";
int res;
printf("thread_one starting\n");
res=pthread_create(&th_one,NULL,(void*)&thread_one,msg)
if(res!=0)
{
exit(EXIT_FAILURE);
}
//sleep(1);//注释 1
printf("thread_two starting\n");
res=pthread_create(&th_two,NULL,(void*)&thread_two,msg)
if(res!=0)
{
exit(EXIT_FAILURE);
}
//sleep(5);//注释 2
printf("Main thread will sleep 1 S\n");
sleep(1);//注释 3
return 0;

}
static void thread_one(char* msg)
{
int i=0;
while(i<6)
{
printf("I am one. loop %d\n",i);
i++;
//sleep(1);//注释 4
}
}
static void thread_two(char* msg)
{
int i=0;
while(i<6)
{
printf("I am two. loop %d\n",i);
i++;
//sleep(1);//注释 5
}
}

测试情况如下:

(1)所有注释均处于注释状态

测试结果也是处于混乱状态(可能与多核处理器有关,单核依靠上下文切换来实现多线程的运行可能结果会一致)

(2)除了注释 3 之外其他注释均处于注释状态

由运行结果来看顺序杂乱,主线程和子线程都在抢夺资源,谁优先抢到则优先执行!由此可以理解结果会多样化的情形!

(3)除注释 3 外其他均注释

由实验结果可知结果不会在多样化因为在主线程中使用 sleep(5),在这 5 秒的时间里面足够子线程运行结束,其实这种情况实在数据量较少的情况下,若循环足够多,其实输出的结果并不像是一个子线程运行完在运行另外一个子线程,中间会出现交叉输出,这就是互相争夺资源的体现。

结论

由此可见,多线程中子线程的执行是在主线程有空闲的条件下。即如果主线程忙,或者是没有执行等待那么,子线程是不会执行的。

其实也不然在多核处理器下也会出现不一致情形,拿第一种情况来说上面的说法结果只有一种情况就是按顺行执行,其实情况也是多种的读者可以自己测试一下!这个涉及到线程同步问题后续会详解!


Deeplearn, 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明从零学习 linux 多线程编程_第一篇
喜欢 (0)
admin
关于作者:
互联网行业码农一枚/业余铲屎官/数码影音爱好者/二次元

您必须 登录 才能发表评论!