您的位置:首页 > 其它

线程的控制与分离

2016-04-19 19:25 489 查看
一.线程的概念
(1)线程是能够独立调度和分派的基本单位;

(2)线程中的实体基本上不拥有系统资源,只是有一点必不可少的,能保证其独立运行的资源;

(3)在一个进程中的多个线程之间可并发执行;同样,不同进程中的线程也能并发执行。

(4)在同一进程中的各个线程都可以共享该进程所拥有的资源,这表现在所有线程都具有与相同的地址空间。
因此,Text Segment,Datd Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:

a.文件描述符表

b.每种信号的处理方式(SIG_IGN,SIG_DFL或者自定义的信号处理函数)

c.当前工作目录

d.用户id和组id

但有些资源是每个线程私有的:

a.线程id

b.上下文,包括各种寄存器的值,程序计数器和栈指针

c.栈空间

d.errno变量

e.信号屏蔽字

f.调度优先级

将要学习的线程库函数是由POSIX标准定义的,称为POSIX thread或pthread,在Linux上线程函数位于libpthread共享库中,因此在编译时要加上-lpthread选项。

二.线程控制

(1)创建线程

#include<pthread.h>
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,
void *(start_routine)(void *),void *arg);
返回值:成功返回0,失败返回错误号。
以前学过的系统函数都是成功返回0,失败返回-1;而错误号保存在全局变量errno中,而pthread库的函数都是通过返回值返回错误号。虽然每个线程也都有一个errno,但这是为了兼容其他函数接口而提供的,Pthread库本身并不使用它,通过返回值返回错误码更加清晰。

在一个线程中调用pthread_create()创建新的线程之后,当前线程从pthread_create()返回继续往下执行,而新的线程所执行的代码由我们传给pthread_create的函数指针start_routine决定。start_routine函数接收一个参数,是通过pthread_create的arg参数传递给它的,该参数的类型为void*,这个指针类型按什么解释根据调用者自己定义。start_routine的返回值类型也是void*,这个指针的含义也由调用者自己定义。start_routine返回时,这个线程就退出了,其他线程可以调用pthread_join得到start_routine的返回值。

pthread_create成功返回后,新创建的线程的id被填写到thread参数所指向的内存单元,进程id的类型是pid_t,每个进程的id在系统中是惟一的,调用getpid(2)可以获得当前进程的id,是一个正整数值。线程id 的类型是thread_t,它只在当前进程中保证是惟一的,在不同的系统中thread_t这个类型有不同的实现,它可能是一个整数值,也可能是一个结构体,也可能是一个地址,因此不能用printf打印,调用pthread_self(3)可以获得当前线程的id。

attr参数表示线程属性,我们默认为NULL,表示线程属性取缺省值。

代码实现如下:
1 #include<stdio.h>
2 #include<pthread.h>
3 #include<unistd.h>
4 #include<sys/types.h>
5
6 void *thread_run(void *arg)
7 {
8 int count=3;
9 printf("this is thread. pid is:%d,pthread id:%u\n",(int)getpid(),pth read_self());
10 return ((void*)5);
11 }
12 int main()
13 {
14 pthread_t tid;
15 int ret=pthread_create(&tid,NULL,thread_run,NULL);
16 if(ret!=0)
17 {
18 printf("create pthread fail.info is:%s\n",strerror(ret));
19 return -1;
20 }
21 sleep(3);
22 printf("this is main thread. pid is:%d,pthread id:%u\n",(int )getpid (),pthread_self());
23 return 0;
24 }
运行结果:



三.终止线程
如果只需要终止某个线程而不是终止整个进程,有三种办法:

(1)从线程函数return;这种方法对主线程不适用,从main函数return相当于调用exit;

(2)一个线程可以调用pthread_cancel终止同一进程中的另一个线程;

(3)线程可以调用pthread_exit终止自己。

注意:pthread_exit 或return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配。因为当其他线程得到这个返回指针时线程函数已经退出了。
四.线程等待
函数原型:int pthread_join(pthread_t thread,void **retval);
返回值:成功返回0,失败返回错误号。

调用该函数的线程将挂起等待,直到id为thread的线程终止。thread以不同的方式终止,通过pthread_join()得到的终止状态是不同的,总结如下:

(1)如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。

(2)如果thread线程被别的线程调用pthread_cancel异常终止,value_ptr所指向的单元里存放的是PTHREAD_CANCELED。

(3)如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元里存放的是传给pthread_exit的参数。

实现代码如下:

1 #include<stdio.h>
2 #include<pthread.h>
3 void* thread1(void *arg)
4 {
5 printf("this is thread1.\n");
6 return ((void*)4);
7 }
8 void *thread2(void *arg)
9 {
10 printf("this is thread2.\n");
11 pthread_exit((void*)5);
12 }
13 void *thread3(void *arg)
14 {
15 while(1)
16 {
17 printf("this is thread3.\n");
18 sleep(1);
19 }
20 }
21 int main()
22 {
23 pthread_t tid1,tid2,tid3;
24 pthread_create(&tid1,NULL,thread1,(void*)1);
25 pthread_create(&tid2,NULL,thread2,(void*)2);
26 pthread_create(&tid3,NULL,thread3,(void*)3);
27 sleep(3);
28 void *ret=NULL;
29 pthread_join(tid1,&ret);
30 printf("thread1 id is:%u,,,tid1 return :%d\n",tid1,(int)ret);
31 pthread_join(tid2,&ret);
32 printf("thread2 id is:%u,,,tid2 return :%d\n",tid2,(int)ret);
33 pthread_cancel(tid3);
34 pthread_join(tid3,&ret);
35 printf("thread3 id is:%u,,,tid3 return :%d\n",tid3,(int)ret);
36 return 0;
37 }
运行结果:



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

默认情况下,线程被创建成可结合的。为了避免存储器泄露,每个可结合线程都应该要么被显示的回收,即调用pthread_join;要么通过调用函数pthread_detach被分离。

如果一个可结合线程运行结束但没有被join,则它的状态类似于进程中的僵死状态,即还有一部分资源没有被回收,所以创建线程者应该调用pthread_join来等待线程运行结束,并可得到线程的退出码,回收其资源。

由于调用pthread_join后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此。这时可以在子线程中加入代码:pthread_detach(pthread_self());或者父线程调用:pthread_detach(thread_id);这样可以将该子线程的状态设置为分离的,在该线程运行结束后会自动释放所有的资源。

代码如下:

1 #include<stdio.h>
2 #include<pthread.h>
3 #include<unistd.h>
4 #include<sys/types.h>
5
6 void *thread_run(void *arg)
7 {
8 int count=2;
9 while(count-->0)
10 {
11 pthread_detach(pthread_self());
12 printf("this is thread. pid is:%d,pthread id:%u\n",(int)getp id(),pthread_self());
13 }
14 pthread_exit((void*)2);
15 }
16 int main()
17 {
18 pthread_t tid;
19 int ret=pthread_create(&tid,NULL,thread_run,NULL);
20 int count=3;
21 while(count-->0)
22 {
23 printf("this is main thread. pid is:%d,pthread id:%u\n",(int )getpid(),pthread_self());
24 sleep(1);
25 }
26 sleep(3);
27 pthread_cancel(tid);
28 //pthread_detach(tid);
29 void *status=0;
30 int join=pthread_join(tid,&status);
31 if(join==0)
32 {
33 printf("pthread_join success\n");
34 }
35 else
36 {
37 printf("pthread_join failed\n");
38 }
39 return 0;
40 }
运行结果:




当使用pthread_detach把线程的状态设置为分离的,那么线程在等待时就会失败。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线程 控制 分离