一道多线程面试题

最近突然看协程和并发编程比较多,遇到这样一道题

题目:子线程循环 10 次,接着主线程循环 100 次,接着又回到子线程循环 10 次,接着再回到主线程又循环 100 次,如此循环50次,试写出代码。

参考文档里的代码采用C++11编写,而我,很不幸的,看不懂。

我想我的cpp已经退化到看不见了吧,然后c++11我更加看不懂了,甚至连cpp较为官方的文档都开始采用c++11了

虽然我不会c++11,但是我会lua、c、golang、python、shell,我要报复性的把这个题做了。

C++11

 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
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
using namespace std;
mutex m;
condition_variable cond;
int flag=10;
void fun(int num){
    for(int i=0;i<2;i++){
        unique_lock<mutex> lk(m);//A unique lock is an object that manages a mutex object with unique ownership in both states: locked and unlocked.
        while(flag!=num)
            cond.wait(lk);//在调用wait时会执行lk.unlock()
        for(int j=0;j<num;j++)
            cout<<j<<" ";
        cout<<endl;
        flag=(num==10)?100:10;
        cond.notify_one();//被阻塞的线程唤醒后lk.lock()恢复在调用wait前的状态
    }
}
int main(){
    thread child(fun,10);
    fun(100);
    child.join();
    return 0;
}

Lua

lua的协程使得主从两个thread之间并没有竞争关系,所以很顺畅的就可以把代码写出来,逻辑也十分简单

 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
local thread = coroutine.create(function() 
	for cnt = 1, 5 do
		local tmp = {}
		for i = 1, 10 do
			table.insert(tmp, i)
		end
		print('child: ', table.concat(tmp, ' '))
		coroutine.yield()

		local tmp = {}
		for i = 1, 10 do
			table.insert(tmp, i)
		end
		print('child: ', table.concat(tmp, ' '))
		coroutine.yield()
	end

end)


for i=1, 5 do
	coroutine.resume(thread)
	local tmp = {}
	for i = 1, 100 do
		table.insert(tmp, i)
	end
	print('main: ', table.concat(tmp, ' '))

	print('------------------------------------')

	coroutine.resume(thread)

	local tmp = {}
	for i = 1, 100 do
		table.insert(tmp, i)
	end
	print('main: ', table.concat(tmp, ' '))

	print('====================================')
end
 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

child: 	1 2 3 4 5 6 7 8 9 10
main: 	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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
------------------------------------
child: 	1 2 3 4 5 6 7 8 9 10
main: 	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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
====================================
child: 	1 2 3 4 5 6 7 8 9 10
main: 	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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
------------------------------------
child: 	1 2 3 4 5 6 7 8 9 10
main: 	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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
====================================
child: 	1 2 3 4 5 6 7 8 9 10
main: 	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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
------------------------------------
child: 	1 2 3 4 5 6 7 8 9 10
main: 	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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
====================================
child: 	1 2 3 4 5 6 7 8 9 10
main: 	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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
------------------------------------
child: 	1 2 3 4 5 6 7 8 9 10
main: 	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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
====================================
child: 	1 2 3 4 5 6 7 8 9 10
main: 	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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
------------------------------------
child: 	1 2 3 4 5 6 7 8 9 10
main: 	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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
====================================

c

  • volatile: 使用volatile类型的全局变量和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
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
52
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>

volatile int cond = 0;

void func(int n)
{
	int i = 0, j = 0;
	for(j=0; j<5; j++){
		while(cond != 0)
			sleep(1);
		printf("\n----------------------------------\n");
		printf("child: ");
		for(i=0; i < 10; i++ )
			printf("%d\t", i);
		printf("\n");
		cond = 1;
	}
}

int main()
{
	pthread_t tid;
	int s = pthread_create(&tid, NULL, func, 10);
	if(s != 0){
		printf("pthread_create error for %s", strerror(errno));
		exit(1);
	}

	int i = 0, j = 0;
	for(j=0; j < 5; j++){
		while(cond != 1)
			sleep(1);
		printf("master: ");
		for(i=0; i < 100; i++ )
			printf("%d\t", i);
		printf("\n");
		printf("==================================\n");
		cond = 0;
	}

	s = pthread_join(tid, NULL);
	if(s != 0){
		printf("pthread_join error for %s", strerror(errno));
		exit(1);
	}
}
  • signal: 使用信号,用于进程互相通知对方

  • semop: 使用System V 进行线程同步,控制并发访问

 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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <signal.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

volatile int cond = 0;
int semid;
struct sembuf sem[2];

void func(int n)
{

//	printf("ppid = %d, getpid = %d\n", getppid(), getpid());

	int i = 0, j = 0;
	for(j=0; j<5; j++){

		sem[1].sem_num = 1;
		sem[1].sem_op = -1;
		sem[1].sem_flg = 0;
		semop(semid, &sem[1], 1);

		printf("\n----------------------------------\n");
		printf("child: ");
		for(i=0; i < 10; i++ )
			printf("%d\t", i);
		printf("\n");

		sem[0].sem_num = 0;
		sem[0].sem_op = 1;
		sem[0].sem_flg = 0;
		semop(semid, &sem[0], 1);
	}
}

int main()
{
	semid = semget(IPC_PRIVATE, 2, 0666| IPC_CREAT);
	if(semid < 0){
		printf("semget error for %s", strerror(errno));
		exit(1);
	}

	pthread_t tid;
	int s = pthread_create(&tid, NULL, func, getpid());
	if(s != 0){
		printf("pthread_create error for %s", strerror(errno));
		exit(1);
	}

	int i = 0, j = 0;
	for(j=0; j < 5; j++){

		sem[0].sem_num = 0;
		sem[0].sem_op = -1;
		sem[0].sem_flg = 0;
		sem[1].sem_num = 1;
		sem[1].sem_op = 1;
		sem[1].sem_flg = 0;

		semop(semid, &sem[1], 1);
		semop(semid, &sem[0], 1);

		printf("master: ");
		for(i=0; i < 100; i++ )
			printf("%d\t", i);
		printf("\n");
		printf("==================================\n");

		sem[1].sem_num = 1;
		sem[1].sem_op = 1;
		sem[1].sem_flg = 0;
	}

	s = pthread_join(tid, NULL);
	if(s != 0){
		printf("pthread_join error for %s", strerror(errno));
		exit(1);
	}
}

python

  • python yield

golang

  • goroutine之间可以通过channel进行多任务同步
 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
package main

import "fmt"

var c1 chan int
var c2 chan int

func task(loop int, times int) {

	for i := 0; i < loop; i++ {
		<-c1
		fmt.Println("------------------------------")
		fmt.Print("child: ")
		for j := 0; j < times; j++ {
			fmt.Printf("%d\t", j)
		}
		fmt.Println()
		c2 <- 1
	}
}

func main() {
	times := 100
	loop := 5

	c1 = make(chan int, 1024)
	c2 = make(chan int, 1024)

	go task(loop, 10)

	for i := 0; i < loop; i++ {
		c1 <- 1
		<-c2
		fmt.Print("master: ")
		for j := 0; j < times; j++ {
			fmt.Printf("%d\t", j)
		}
		fmt.Println()
		fmt.Println("==============================")
	}
}
  • 其实golang的chan作为阻塞读取的协程通信组件,有一个也就能实现谁先谁后的同步了;毕竟,不光 val <- chan 这种读操作会堵塞,chan <- val这种写操作也会被堵塞
 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
package main

import "fmt"

var c1 chan int

func task(loop int, times int) {

	for i := 0; i < loop; i++ {

		fmt.Println("------------------------------")
		fmt.Print("child: ")
		for j := 0; j < times; j++ {
			fmt.Printf("%d\t", j)
		}
		fmt.Println()
		c1 <- 1
	}
}

func main() {
	times := 100
	loop := 5

	c1 = make(chan int)
	go task(loop, 10)

	for i := 0; i < loop; i++ {

		<-c1
		fmt.Print("master: ")
		for j := 0; j < times; j++ {
			fmt.Printf("%d\t", j)
		}
		fmt.Println()
		fmt.Println("==============================")
	}
}

shell

  • token bucket
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy