- 对于一个有执行顺序有要求的多线程程序,就是一个线程某一部分的执行要在另一个进行执行完成的条件下进行,我们一般采用的方法就是进行延时等待操作。具体而言就是设置一个标志,在一个线程中一直进行检查,在另一个线程中进行修改。具体代码如下:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
volatile int done = 0;
void* child (void *arg) {
printf("child\n");
done = 1;
return NULL;
}
int main(int argc, char* argv[])
{
printf("parent: begin\n");
pthread_t c;
pthread_create(&c, NULL, child, NULL);
while (done == 0) ;
printf("parend: end\n");
return 0;
}
编译链接之后,可以得到运行效果如下:
可以看到程序确实按照我们的预期进行工作,但是其实在这个过程中,一直父线程和子线程在交替执行,从下面的程序中我们可以看到这个现象。
修改程序如下:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
volatile int done = 0;
void* child (void *arg) {
printf("child\n");
done = 1;
return NULL;
}
int main(int argc, char* argv[])
{
printf("parent: begin\n");
pthread_t c;
pthread_create(&c, NULL, child, NULL);
while (done == 0) {
printf("main thread\n");
}
printf("parend: end\n");
return 0;
}
可以看到,mian thread的执行时间占据到了执行时间的很长一部分,而这一部分是无用的,我们想要的效果是当child thread中的标志位发生改变的时候,main thread才进行执行,而不是一直在执行一些无意义的轮询检查。
- 使用互斥量(mutex)和条件变量(cond)来实现线程之间的执行之间的控制
具体实现的功能和1一致,代码如下:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
volatile int done = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* child (void *arg) {
pthread_mutex_lock(&lock);
printf("child\n");
done = 1;
pthread_cond_signal(&cond);
printf("signal the main thread\n");
pthread_mutex_unlock(&lock);
return NULL;
}
int main(int argc, char* argv[])
{
pthread_t c;
printf("parent: begin\n");
pthread_create(&c, NULL, child, NULL);
pthread_mutex_lock(&lock);
while (done == 0) {
printf("main thread\n");
pthread_cond_wait(&cond, &lock);
}
pthread_mutex_unlock(&lock);
printf("parend: end\n");
return 0;
}
编译完,执行,如下:
可以看到,main thread并没有一直执行轮询方式进行查询标志是否满足,而是让出CPU的执行时间。
具体过程如下:
当main thread执行的时候,创建线程chid,然后child thread进入到就绪状态,但是并没有运行,main thread继续执行,当执行到
p
t
h
r
e
a
d
_
m
u
t
e
x
_
l
o
c
k
pthread\_mutex\_lock
pthread_mutex_lock的时候,main thread会获得到锁,进入到
c
i
r
i
t
i
a
l
s
e
c
t
i
o
n
ciritial\ section
ciritial section,然后此时就算切换到chid thread的时候,child thread也会被阻塞起来,进入到就绪状态,让出CPU的执行时间,后来执行
p
r
i
n
t
f
printf
printf,然后执行
p
t
h
r
e
a
d
_
c
o
n
d
_
w
a
i
t
pthread\_cond\_wait
pthread_cond_wait,此时会释放获得的
l
o
c
k
lock
lock,然后等待对于条件变量
c
o
n
d
cond
cond的唤醒,进入就绪状态。然后child thread就会进入活动状态,获得到
l
o
c
k
lock
lock,然后进行执行,将
d
o
n
e
done
done修改为1,再使用
p
t
h
r
e
a
d
c
o
n
d
s
i
g
n
a
l
pthread_cond_signal
pthreadcondsignal来通知main thread,让其进入就绪态,此时child thread仍然获得锁
l
o
c
k
lock
lock,然后进行执行
p
r
i
n
t
f
printf
printf,随后使用
p
t
h
r
e
a
d
m
u
t
e
x
u
n
l
o
c
k
pthread_mutex_unlock
pthreadmutexunlock释放掉锁,main thread进入到活动态,获得CPU执行时间,就行后序的事情。