12.2 linux下的线程

什么是线程:

  在一个程序里的一个执行路线就叫做线程(thread),更准确的定义是:线程是“一个进程内部的控制序列”

  一切进程至少都有一个执行线程

进程与线程:

  进程是资源竞争的基本单位

  线程是程序执行的最小单位

  线程会使用进程的全局变量

  线程共享进程数据,但也拥有自己的一部分数据

    线程ID

    程序计数器

    寄存器组

    栈

    errno

  一个进程内部的线程可以共享资源

    代码段

    数据段

    打开文件和信号

单线程和多线程模型如下:

 如何从进程往线程中传数据?又如何从线程中将数据传出来呢?

1、使用全局变量,可以将数据传给线程

2、在进程中分配内存,通过pthread_create的第四个参数传给线程

fork和创建新线程的区别:

线程的属性是可以修改的。竞争范围可以修改。

POSIX线程库:

  与线程有关的函数构成了一个完整的系列,绝大多数函数名字都是以“pthread”开头的。

  要使用这些函数库,需要引入头文件<pthread.h>

  链接这些线程函数库时要使用编译器命令的“-lpthread”选项

pthread_create函数:

  原型:int  pthread_create(pthread_t  *thread,  const  pthread_attr_t  *attr,  void *(*start_routine)(void *),  void  *arg)

  功能:创建一个新的线程

  参数:

    thread:返回的线程ID

    attr:设置线程的属性,attr为NULL表示使用默认属性

    start_routine:是一个函数地址,线程启动后要执行的函数

    arg:传给线程启动函数的参数

  返回值:成功返回0,失败返回错误码

错误检查:

  传统的一些函数是成功返回0,失败返回-1,并且对全局变量errno赋值以指示错误

  pthreads函数出错时不会设置全局变量errno(而大部分其他POSIX函数会这样做),而是将错误码通过返回值返回

  pthread同样也提供了线程内的errno变量,以支持其他使用errno的代码,对于pthreads函数的错误,建议通过返回值来判定,因为读取返回值

  要比读取线程内的errno变量的开销更小。

其他线程函数:

 

进程和线程对比:

进程:

  fork;有pid;有pcb控制块;有僵尸进程;

线程:

  pthread_create;有tid;有tcb控制块;有僵尸线程

线程和进程有一个巨大的区别,就是线程依赖进程,如果进程死了,线程也会死掉。而进程是父进程死了,子进程依旧可以运行。因为进程有自己独立的内存空间。总之,线程依赖于进程的生命周期。

线程示例程序如下:

 1 #include <unistd.h>
 2 #include <sys/types.h>
 3 
 4 #include <stdlib.h>
 5 #include <stdio.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 #include <pthread.h>
 9 /*
10 int pthread_create(pthread_t *restrict thread,
11            const pthread_attr_t *restrict attr,
12            void *(*start_routine)(void*), void *restrict arg);
13 */
14 
15 void *start_routine(void *arg)
16 {
17     int i = 0;
18     printf("I am thread. 
");
19     
20     for(i = 0; i < 10; i++)
21     printf("B");
22     fflush(stdout);
23     
24     return NULL;
25 }
26 
27 int main()
28 {
29     pthread_t thread;
30     int i = 0;
31     
32     pthread_create(&thread, NULL, start_routine, NULL);
33     
34     for(i = 0; i< 10; i++)
35     {
36         printf("A");
37         fflush(stdout);
38     }
39     
40     return 0;
41 }

执行完32行,线程就去执行线程体函数了,34行开始的for循环已经不再属于线程,也就是说线程执行完线程体就返回了,不会执行到34行。

运行结果如下:

我们看到只打印出了AAAAAAAAA,这是因为,进程(主线程)死了之后,线程也就死了,它还没有来得及执行线程体就死了。我们给进程下面加上sleep,如下:

 1 #include <unistd.h>
 2 #include <sys/types.h>
 3 
 4 #include <stdlib.h>
 5 #include <stdio.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 #include <pthread.h>
 9 /*
10 int pthread_create(pthread_t *restrict thread,
11            const pthread_attr_t *restrict attr,
12            void *(*start_routine)(void*), void *restrict arg);
13 */
14 
15 void *start_routine(void *arg)
16 {
17     int i = 0;
18     printf("I am thread. 
");
19     
20     for(i = 0; i < 10; i++)
21     printf("B");
22     fflush(stdout);
23     
24     return NULL;
25 }
26 
27 int main()
28 {
29     pthread_t thread;
30     int i = 0;
31     
32     pthread_create(&thread, NULL, start_routine, NULL);
33     
34     for(i = 0; i< 10; i++)
35     {
36         printf("A");
37         fflush(stdout);
38     }
39     
40     sleep(2);
41     
42     return 0;
43 }

结果如下:

我们看到线程成功打印出了数据。

 打印全局变量,程序如下:

 1 #include <unistd.h>
 2 #include <sys/types.h>
 3 
 4 #include <stdlib.h>
 5 #include <stdio.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 #include <pthread.h>
 9 /*
10 int pthread_create(pthread_t *restrict thread,
11            const pthread_attr_t *restrict attr,
12            void *(*start_routine)(void*), void *restrict arg);
13 */
14 
15 int g_num = 0;
16 
17 void *start_routine(void *arg)
18 {
19     int i = 0;
20     printf("I am thread. 
");
21     printf("g_num = %d
", g_num);
22     
23     for(i = 0; i < 10; i++)
24     {
25         printf("B");
26         fflush(stdout);
27     }
28     
29     printf("
");
30     
31     return NULL;
32 }
33 
34 int main()
35 {
36     pthread_t thread;
37     int i = 0;
38     
39     g_num = 10;
40     
41     pthread_create(&thread, NULL, start_routine, NULL);
42     
43     for(i = 0; i< 10; i++)
44     {
45         printf("A");
46         fflush(stdout);
47     }
48     printf("
");
49     sleep(2);
50     
51     return 0;
52 }

执行结果如下:

多进程打印全局变量程序如下:

 1 #include <unistd.h>
 2 #include <sys/types.h>
 3 
 4 #include <stdlib.h>
 5 #include <stdio.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 #include <pthread.h>
 9 /*
10 int pthread_create(pthread_t *restrict thread,
11            const pthread_attr_t *restrict attr,
12            void *(*start_routine)(void*), void *restrict arg);
13 */
14 
15 int g_num = 0;
16 
17 void *start_routine(void *arg)
18 {
19     int i = 0;
20     printf("I am thread. 
");
21     printf("g_num = %d
", g_num);
22     
23     for(i = 0; i < 10; i++)
24     {
25         printf("B");
26         fflush(stdout);
27     }
28     
29     printf("
");
30     
31     return NULL;
32 }
33 
34 int main()
35 {
36     pid_t pid;
37     int i = 0;
38     
39     g_num = 10;
40     
41     pid = fork();
42     
43     if( pid == 0)
44     {
45         printf("I am child 
");
46         printf("g_num = %d
", g_num);
47         for(i = 0; i< 10; i++)
48         {
49             printf("B");
50             fflush(stdout);
51         }
52         printf("
");
53         exit(0);
54     }
55     
56     for(i = 0; i< 10; i++)
57     {
58         printf("A");
59         fflush(stdout);
60     }
61     printf("
");
62     sleep(2);
63     
64     return 0;
65 }

结果如下:

 获取线程ID的示例:

 1 #include <unistd.h>
 2 #include <sys/types.h>
 3 
 4 #include <stdlib.h>
 5 #include <stdio.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 #include <pthread.h>
 9 /*
10 int pthread_create(pthread_t *restrict thread,
11            const pthread_attr_t *restrict attr,
12            void *(*start_routine)(void*), void *restrict arg);
13 */
14 
15 int g_num = 0;
16 
17 void *start_routine(void *arg)
18 {
19     int i = 0;
20     printf("I am thread. 
");
21     printf("g_num = %d
", g_num);
22     printf("thread id = %lu
", pthread_self());
23     
24     for(i = 0; i < 10; i++)
25     {
26         printf("B");
27         fflush(stdout);
28     }
29     
30     printf("
");
31     
32     return NULL;
33 }
34 
35 int main()
36 {
37     pthread_t thread;
38     int i = 0;
39     
40     g_num = 10;
41     
42     pthread_create(&thread, NULL, start_routine, NULL);
43     
44     for(i = 0; i< 10; i++)
45     {
46         printf("A");
47         fflush(stdout);
48     }
49     printf("
");
50     sleep(2);
51     
52     return 0;
53 }

结果如下:

 上面的程序中,我们使用sleep等待,让子进程先运行,但是这不是根本的解决办法,我们使用pthread_join等待子线程退出,程序如下:

 1 #include <unistd.h>
 2 #include <sys/types.h>
 3 
 4 #include <stdlib.h>
 5 #include <stdio.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 #include <pthread.h>
 9 /*
10 int pthread_create(pthread_t *restrict thread,
11            const pthread_attr_t *restrict attr,
12            void *(*start_routine)(void*), void *restrict arg);
13 */
14 
15 int g_num = 0;
16 
17 void *start_routine(void *arg)
18 {
19     int i = 0;
20     printf("I am thread. 
");
21     printf("g_num = %d
", g_num);
22     printf("thread id = %lu
", pthread_self());
23     
24     for(i = 0; i < 10; i++)
25     {
26         printf("B");
27         fflush(stdout);
28     }
29     
30     sleep(3);
31     
32     printf("
");
33     
34     return NULL;
35 }
36 
37 int main()
38 {
39     pthread_t thread;
40     int i = 0;
41     
42     g_num = 10;
43     
44     pthread_create(&thread, NULL, start_routine, NULL);
45     
46     for(i = 0; i< 10; i++)
47     {
48         printf("A");
49         fflush(stdout);
50     }
51     printf("
");
52     
53     pthread_join(thread, NULL);
54     
55     return 0;
56 }

结果如下:

线程有两种死掉的方法,一个是自杀一个是他杀。

我们先用exit使子线程退出,程序如下:

 1 #include <unistd.h>
 2 #include <sys/types.h>
 3 
 4 #include <stdlib.h>
 5 #include <stdio.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 #include <pthread.h>
 9 /*
10 int pthread_create(pthread_t *restrict thread,
11            const pthread_attr_t *restrict attr,
12            void *(*start_routine)(void*), void *restrict arg);
13 */
14 
15 int g_num = 0;
16 
17 void *start_routine(void *arg)
18 {
19     int i = 0;
20     printf("I am thread. 
");
21     printf("g_num = %d
", g_num);
22     printf("thread id = %lu
", pthread_self());
23     
24     for(i = 0; i < 10; i++)
25     {
26         printf("B");
27         fflush(stdout);
28     }
29     
30     sleep(3);
31     
32     printf("
");
33     
34     exit(0);
35 }
36 
37 int main()
38 {
39     pthread_t thread;
40     int i = 0;
41     
42     g_num = 10;
43     
44     pthread_create(&thread, NULL, start_routine, NULL);
45     
46     for(i = 0; i< 10; i++)
47     {
48         printf("A");
49         fflush(stdout);
50     }
51     printf("
");
52     
53     pthread_join(thread, NULL);
54     printf("child thread die
");
55     
56     return 0;
57 }

结果如下:

我们发现子线程退出后,父进程没有打印出第54行的数据,说明子线程用exit退出后,父进程也挂了,相当于同归于尽。因此,线程退出千万不能用exit。

 我们可以使用pthread_exit让线程死掉,程序如下:

 1 #include <unistd.h>
 2 #include <sys/types.h>
 3 
 4 #include <stdlib.h>
 5 #include <stdio.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 #include <pthread.h>
 9 /*
10 int pthread_create(pthread_t *restrict thread,
11            const pthread_attr_t *restrict attr,
12            void *(*start_routine)(void*), void *restrict arg);
13 */
14 
15 int g_num = 0;
16 
17 void *start_routine(void *arg)
18 {
19     int i = 0;
20     printf("I am thread. 
");
21     printf("g_num = %d
", g_num);
22     printf("thread id = %lu
", pthread_self());
23     
24     for(i = 0; i < 10; i++)
25     {
26         printf("B");
27         fflush(stdout);
28     }
29     
30     sleep(3);
31     
32     printf("
");
33     
34     pthread_exit(NULL);
35 }
36 
37 int main()
38 {
39     pthread_t thread;
40     int i = 0;
41     
42     g_num = 10;
43     
44     pthread_create(&thread, NULL, start_routine, NULL);
45     
46     for(i = 0; i< 10; i++)
47     {
48         printf("A");
49         fflush(stdout);
50     }
51     printf("
");
52     
53     pthread_join(thread, NULL);
54     printf("child thread die
");
55     
56     return 0;
57 }

执行结果如下:

可以看到第54行打印出来了。

线程他杀就是父进程调用pthread_cancel杀掉子线程,这个很少用。

父进程如果不想等待线程结束,可以让线程脱离这个进程运行,使用pthread_detach函数,程序如下:

 1 #include <unistd.h>
 2 #include <sys/types.h>
 3 
 4 #include <stdlib.h>
 5 #include <stdio.h>
 6 #include <errno.h>
 7 #include <string.h>
 8 #include <pthread.h>
 9 /*
10 int pthread_create(pthread_t *restrict thread,
11            const pthread_attr_t *restrict attr,
12            void *(*start_routine)(void*), void *restrict arg);
13 */
14 
15 int g_num = 0;
16 
17 void *start_routine(void *arg)
18 {
19     int i = 0;
20     pthread_detach(pthread_self());
21     printf("I am thread. 
");
22     printf("g_num = %d
", g_num);
23     printf("thread id = %lu
", pthread_self());
24     
25     for(i = 0; i < 10; i++)
26     {
27         printf("B");
28         fflush(stdout);
29     }
30     
31     sleep(3);
32     
33     printf("
");
34     
35     pthread_exit(NULL);
36 }
37 
38 int main()
39 {
40     pthread_t thread;
41     int i = 0;
42     
43     g_num = 10;
44     
45     pthread_create(&thread, NULL, start_routine, NULL);
46     
47     for(i = 0; i< 10; i++)
48     {
49         printf("A");
50         fflush(stdout);
51     }
52     printf("
");
53     
54     pthread_join(thread, NULL);
55     printf("child thread die
");
56     
57     return 0;
58 }

结果如下:

一般在线程体函数中立即调用pthread_detach函数。

我们编译多线程程序时要加上 -lpthread,使用ldd可以查看程序用了哪些动态库,如下所示:

 可以使用nm查看一个库中的函数(符号),如下:

原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9451732.html