用户级:创建开销小,由线程库直接管理。无法使用多处理器资源
内核级:创建开销大,由内核直接管理。可以使用多处理器的资源
Linux实现线程的机制非常独特。从内核的角度来说,它并没有线程这个概念。Linux把所有的线程都当作进程来实现。内核并没有准备特别的调度算法或是定义特别的数据结构来表征线程。相反,线程仅仅被视为一个与其他进程共享某些资源的进程。每个线程都拥有唯一隶属于自己的task_struct,所以在内核中,它看起来就就像是一个普通的进程(只是该进程和其他一些进程共享某些资源,如地址空间)。
线程安全:简单来说线程安全就是多个线程并发同一段代码时,不会出现不同的结果,我们就可以说该线程是安全的。
strtok()函数不能在多线程中使用
例如下面的函数:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<unistd.h>
5 #include<string.h>
6 #include<pthread.h>
7
8 void* fun(void * arg)
9 {
10 char buff[] = {
"1 2 3 4 5 6 7 8 9"};
11 char *s = strtok(buff," ");
12 while( s != NULL )
13 {
14 printf("fun s = %s\n",s);
15 sleep(1);
16 s = strtok(NULL," ");
17 }
18 }
19
21 int main()
22 {
23 pthread_t id;
24 pthread_create(&id,NULL,fun,NULL);
25
26 char str[] = {
"a b c d e f g k l"};
27
28 char *p = strtok(str," ");
29 while( p != NULL)
30 {
31 printf("p = %s\n",p);
32 sleep(1);
33 p = strtok(NULL," ");
34 }
35
36 pthread_join(id,NULL);
37 }
改进方法:使用strtok_r()函数:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<unistd.h>
5 #include<string.h>
6 #include<pthread.h>
7
8 void* fun(void * arg)
9 {
10 char buff[] = {
"1 2 3 4 5 6 7 8 9"};
11 char * ptr = NULL;
12 char *s = strtok_r(buff," ",&ptr);
13 while( s != NULL )
14 {
15 printf("fun s = %s\n",s);
16 sleep(1);
17 s = strtok_r(NULL," ",&ptr);
18 }
19 }
20
21 int main()
22 {
23 pthread_t id;
24 pthread_create(&id,NULL,fun,NULL);
25
26 char str[] = {
"a b c d e f g k l"};
27 char *ptr = NULL;
28 char *p = strtok_r(str," ",&ptr);
29 while( p != NULL)
30 {
31 printf("p = %s\n",p);
32 sleep(1);
33 p = strtok_r(NULL," ",&ptr);
34 }
35
36 pthread_join(id,NULL);
37 }
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<unistd.h>
5 #include<string.h>
6 #include<pthread.h>
7
8 void* fun(void * arg)
9 {
10 while(1)
11 {
12 sleep(1);
13 }
14 }
15
16 int main()
17 {
18 pthread_t id;
19 int i = 0;
20 for(l;i<10000;i++)
21 {
22 int res = pthread_create(&id,NULL,fun,NULL);
23 if(res != 0)
24 {
25 break;
26 }
27 printf("i = %d\n",i);
28 }
29
30 pthread_join(id,NULL);
31 }
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<unistd.h>
5 #include<string.h>
6 #include<pthread.h>
7
8 void *fun(void* arg)
9 {
10 fork();
11
12 int i = 0;
13 for(;i<5;i++)
14 {
15 printf("fun run pid = %d\n",getpid());
16 sleep(1);
17 }
18 }
19 int main()
20 {
21 pthread_t id;
22 pthread_create(&id,NULL,fun,NULL);
23
24 int i = 0;
25 for(;i<5;i++)
26 {
27 printf("main run pid = %d\n",getpid());
28 sleep(1);
29 }
30 }
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<unistd.h>
5 #include<string.h>
6 #include<pthread.h>
7 #include<sys/wait.h>
8 pthread_mutex_t mutex;
9
10 void *fun(void* arg)
11 {
12
13 pthread_mutex_lock(&mutex);
14 printf("fun lock!\n");
15 sleep(5);
16 pthread_mutex_unlock(&mutex);
17 printf("fun unlock\n");
18 }
19 int main()
20 {
21 pthread_t id;
22 pthread_mutex_init(&mutex,NULL);
23 pthread_create(&id,NULL,fun,NULL);
24 sleep(1);
25
26 pid_t pid = fork();
27 assert(pid != -1);
28
29 if(pid == 0)
30 {
31 printf("child lock start\n");
32 pthread_mutex_lock(&mutex);
33 printf("child lock success!\n");
34 pthread_mutex_unlock(&mutex);
35 exit(0);
36 }
37 wait(NULL);
38 printf("main over\n");
39 }
fork()会复制父进程的锁,初始状态由复制时父进程中锁的状态决定。所以该程序会阻塞
解决办法:使用pthread_atfork()对fork进行限制,fork之前加锁,之后解锁。
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<unistd.h>
5 #include<string.h>
6 #include<pthread.h>
7 #include<sys/wait.h>
8 pthread_mutex_t mutex;
9
10 void fun_lock()
11 {
12 pthread_mutex_lock(&mutex);
13
14 }
15
16 void fun_unlock()
17 {
18 pthread_mutex_unlock(&mutex);
19 }
20 void *fun(void* arg)
21 {
22
23 pthread_mutex_lock(&mutex);
24 printf("fun lock!\n");
25 sleep(5);
26 pthread_mutex_unlock(&mutex);
27 printf("fun unlock\n");
28 }
29 int main()
30 {
31 pthread_atfork(fun_lock,fun_unlock,fun_unlock);
32 pthread_t id;
33 pthread_mutex_init(&mutex,NULL);
34 pthread_create(&id,NULL,fun,NULL);
35 sleep(1);
36
37 pid_t pid = fork();
38 assert(pid != -1);
39
40 if(pid == 0)
41 {
42 printf("child lock start\n");
43 pthread_mutex_lock(&mutex);
44 printf("child lock success!\n");
45 pthread_mutex_unlock(&mutex);
46 exit(0);
47 }
48 wait(NULL);
49 printf("main over\n");
50 }
题目说明:三个线程,第一个线程输出A,第二个线程输出B,第三个线程输出C(要求:第一个要输出A,A输出完成之后才能输出B,B输出完成之后才能输出C。例如:ABCABCABC)
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<assert.h>
4 #include<unistd.h>
5 #include<string.h>
6 #include<pthread.h>
7 #include<semaphore.h>
8
9 sem_t sem1;
10 sem_t sem2;
11 sem_t sem3;
12
13
14 void* fun1(void* arg)
15 {
16 int i = 0;
17 for(;i<5;i++)
18 {
19 sem_wait(&sem1);//ps1
20 printf("A");
21 fflush(stdout);
22 sem_post(&sem2);//vs2
23 }
24 }
25
26 void* fun2(void* arg)
27 {
28 int i = 0;
29 for(;i<5;i++)
30 {
31 sem_wait(&sem2);//ps2
32 printf("B");
33 fflush(stdout);
34 sem_post(&sem3);//vs3
35 }
36 }
37 void* fun3(void* arg)
38 {
39 int i = 0;
40 for(;i<5;i++)
41 {
42 sem_wait(&sem3);//ps3
43 printf("C");
44 fflush(stdout);
45 sem_post(&sem1);//vs1
46 }
47 }
48 int main()
49 {
50 sem_init(&sem1,0,1);
51 sem_init(&sem2,0,0);
52 sem_init(&sem3,0,0);
53
54 pthread_t id[3];
55 pthread_create(&id[0],NULL,fun1,NULL);
56 pthread_create(&id[1],NULL,fun2,NULL);
57 pthread_create(&id[2],NULL,fun3,NULL);
58
59 int i = 0;
60 for(;i<3;i++)
61 {
62 pthread_join(id[i],NULL);
63 }
64
65 sem_destroy(&sem1);
66 sem_destroy(&sem2);
67 sem_destroy(&sem3);
68
69
70 }
输出结果:ABCABCABCABCABC