2021-05-02

c/c++多线程和线程同步


文章还没写完呢

c/c++线程的使用

编译-l指定动态链接库pthread

1
gcc xxx.c -lpthread -o xxx 

1.线程创建

pthread_t是long类型的线程id
pthread_create时callback调用子线程执行的函数,第四个参数是callback传入的void* arg
sleep让子线程执行完再挂断主线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void* callback(void* arg) {
for (int i = 0; i < 5; i++) {
printf("子线程i=: %d\n", i);
}
printf("子线程id: %ld\n", pthread_self());
return NULL;
}

int main() {
pthread_t tid;
pthread_create(&tid, NULL, callback, NULL);
for (int i = 0; i < 5; i++) {
printf("主线程i=: %d\n", i);
}
printf("主线程id: %ld\n", pthread_self());
sleep(1);
return 0;
}

2.线程退出

主线程退出,子线程变主,回收空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void* callback(void* arg) {
for (int i = 0; i < 5; i++) {
printf("子线程i=: %d\n", i);
}
printf("子线程id: %ld\n", pthread_self());
return NULL;
}

int main() {
pthread_t tid;
pthread_create(&tid, NULL, callback, NULL);
//for (int i = 0; i < 5; i++) {
// printf("主线程i=: %d\n", i);
//}
printf("主线程id: %ld\n", pthread_self());
//sleep(1);
pthread_exit(NULL);
return 0;
}

3.线程回收

join会让主线程阻塞
接受个Test的struct作为资源
直接在子线程开struct Test t会开在栈空间,回收后释放了,主线程肯定拿不到这个资源
要么:struct Test t开在全局变量,join后拿到Test,然后强转下struct Test* pt = (struct Test*)ptr;
要么:在主线程里开struct Test t,然后pthread_join(tid, &ptr)给子线程,子线程在arg拿到,也要强转下struct Test* t = (struct Test*)arg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

struct Test {
int num;
int age;
};

//struct Test t; //开在这里

void* callback(void* arg) {
for (int i = 0; i < 5; i++) {
printf("子线程i=: %d\n", i);
}
printf("子线程id: %ld\n", pthread_self());

struct Test* t = (struct Test*)arg;
t->num = 100;
t->age = 22;

pthread_exit(&t); //Test t如果是在子线程中开栈空间后会被释放

return NULL;
}

int main() {
struct Test t; //或者开在这里
pthread_t tid;
pthread_create(&tid, NULL, callback, &t);
//for (int i = 0; i < 5; i++) {
// printf("主线程i=: %d\n", i);
//}
printf("主线程id: %ld\n", pthread_self());
//sleep(1);
//pthread_exit(NULL);
void* ptr;
pthread_join(tid, &ptr);
//struct Test* pt = (struct Test*)ptr;
printf("%主线程: pt.num=%d, pt.age=%d\n", t.num, t.age);
return 0;
}

4.线程分离

让主线程退出后不会释放子线程的资源
这里子线程创建后和主线程分离,子线程死后由内核调度回收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

struct Test {
int num;
int age;
};

void* callback(void* arg) {
for (int i = 0; i < 5; i++) {
printf("子线程i=: %d\n", i);
}
printf("子线程id: %ld\n", pthread_self());

struct Test* t = (struct Test*)arg;
t->num = 100;
t->age = 22;

pthread_exit(&t);

return NULL;
}

int main() {
struct Test t; //或者开在这里
pthread_t tid;
pthread_create(&tid, NULL, callback, &t);
printf("主线程id: %ld\n", pthread_self());

pthread_detach(tid);
pthread_exit(NULL);

return 0;
}

5.其他线程函数

pthread_cancel退出子线程,但是会在系统调用之后(printf就是)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

struct Test {
int num;
int age;
};

void* callback(void* arg) {
for (int i = 0; i < 5; i++) {
printf("子线程i=: %d\n", i);
}
printf("子线程id: %ld\n", pthread_self()); //printf系统调用了

struct Test* t = (struct Test*)arg;
t->num = 100;
t->age = 22;

pthread_exit(&t);

return NULL;
}

int main() {
struct Test t; //或者开在这里
pthread_t tid;
pthread_create(&tid, NULL, callback, &t);
printf("主线程id: %ld\n", pthread_self());

pthread_detach(tid);
pthread_cancel(tid); //杀死子进程

pthread_exit(NULL); //主线程退出


return 0;
}

c/c++线程的同步和互斥锁

不同步

很明显这没有同步,最后不是100

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

int number = 0; //全局资源

void* funcA(void* arg) {
for (int i = 0; i < 50; i++) {
int cur = number;
cur++;
usleep(10);
number = cur;
printf("Thread A, id = %lu, number = %d\n", pthread_self(), number);
}
return NULL;
}

void* funcB(void* arg) {
for (int i = 0; i < 50; i++) {
int cur = number;
cur++;
number = cur;
usleep(5);
printf("Thread B, id = %lu, number = %d\n", pthread_self(), number);
}
return NULL;
}

int main() {
pthread_t p1, p2;

pthread_create(&p1, NULL, funcA, NULL);
pthread_create(&p2, NULL, funcB, NULL);

// 阻塞 & 回收
pthread_join(p1, NULL);
pthread_join(p2, NULL);

return 0;
}

互斥锁

锁:状态(锁/没锁);加锁信息(线程id)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

int number = 0; //全局资源
pthread_mutex_t mutex;

void* funcA(void* arg) {
for (int i = 0; i < 50; i++) {
pthread_mutex_lock(&mutex);
int cur = number;
cur++;
usleep(10);
number = cur;
pthread_mutex_unlock(&mutex);
printf("Thread A, id = %lu, number = %d\n", pthread_self(), number);
}
return NULL;
}

void* funcB(void* arg) {
for (int i = 0; i < 50; i++) {
pthread_mutex_lock(&mutex);
int cur = number;
cur++;
number = cur;
pthread_mutex_unlock(&mutex);
printf("Thread B, id = %lu, number = %d\n", pthread_self(), number);
usleep(5);
}
return NULL;
}

int main() {
pthread_t p1, p2;

pthread_mutex_init(&mutex, NULL);

pthread_create(&p1, NULL, funcA, NULL);
pthread_create(&p2, NULL, funcB, NULL);

// 阻塞 & 回收
pthread_join(p1, NULL);
pthread_join(p2, NULL);

pthread_mutex_destroy(&mutex);

return 0;
}