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

4,608次阅读
没有评论

共计 3057 个字符,预计需要花费 8 分钟才能阅读完成。

概念–线程

线程(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之外其他注释均处于注释状态

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

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

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

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

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

结论

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

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

正文完
请博主喝杯咖啡吧!
post-qrcode
 
admin
版权声明:本站原创文章,由 admin 2015-05-30发表,共计3057字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码