参考资料:
a.对线程进行操作的API
pthread_create用于创建一个线程,成功返回0,否则返回Exxx(为正数)。
pthread_join用于等待某个线程退出,成功返回0,否则返回Exxx(为正数)。
pthread_self用于返回当前线程的ID。
pthread_detach用于是指定线程变为分离状态,就像进程脱离终端而变为后台进程类似。成功返回0,否则返回Exxx(为正数)。变为分离状态的线程,如果线程退出,它的所有资源将全部释放。而如果不是分离状态,线程必须保留它的线程ID,退出状态直到其它线程对它调用了pthread_join。
pthread_exit用于终止线程,可以指定返回值,以便其他线程通过pthread_join函数获取该线程的返回值。
在对临界资源进行操作之前需要 pthread_mutex_lock 先加锁,操作完之后 pthread_mutex_unlock 再解锁。而且在这之前需要声明一个 pthread_mutex_t 类型的变量,用作前面两个函数的参数#include <pthread.h>pthread_cond_wait用于等待某个特定的条件为真,pthread_cond_signal用于通知阻塞的线程某个特定的条件为真了。在调用者两个函数之前需要声明一个pthread_cond_t类型的变量,用于这两个函数的参数。
为什么条件变量始终与互斥锁一起使用,对条件的测试是在互斥锁(互斥)的保护下进行的呢?因为“某个特性条件”通常是在多个线程之间共享的某个变量。互斥锁允许这个变量可以在不同的线程中设置和检测。
通常,pthread_cond_wait只是唤醒等待某个条件变量的一个线程。如果需要唤醒所有等待某个条件变量的线程,需要调用:
int pthread_cond_broadcast (pthread_cond_t * cptr);默认情况下面,阻塞的线程会一直等待,知道某个条件变量为真。如果想设置最大的阻塞时间可以调用:
int pthread_cond_timedwait (pthread_cond_t * cptr, pthread_mutex_t *mptr, const struct timespec *abstime);如果时间到了,条件变量还没有为真,仍然返回,返回值为ETIME。
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);int pthread_mutex_destroy(pthread_mutex_t *mutex); int pthread_mutex_lock(pthread_mutex_t * mptr); int pthread_mutex_unlock(pthread_mutex_t * mptr);
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond); int pthread_cond_wait(pthread_cond_t *cptr, pthread_mutex_t *mptr); int pthread_cond_signal(pthread_cond_t *cptr);
int pthread_cond_broadcast (pthread_cond_t * cptr);int pthread_cond_timedwait (pthread_cond_t * cptr, pthread_mutex_t *mptr, const struct timespec *abstime);pthread_cond_wait用于等待某个特定的条件为真,pthread_cond_signal用于通知阻塞的线程某个特定的条件为真了。在调用者两个函数之前需要声明一个pthread_cond_t类型的变量,用于这两个函数的参数。
为什么条件变量始终与互斥锁一起使用,对条件的测试是在互斥锁(互斥)的保护下进行的呢?因为“某个特性条件”通常是在多个线程之间共享的某个变量。互斥锁允许这个变量可以在不同的线程中设置和检测。
通常,pthread_cond_wait只是唤醒等待某个条件变量的一个线程。如果需要唤醒所有等待某个条件变量的线程,需要调用:
int pthread_cond_broadcast (pthread_cond_t * cptr);默认情况下面,阻塞的线程会一直等待,知道某个条件变量为真。如果想设置最大的阻塞时间可以调用:
int pthread_cond_timedwait (pthread_cond_t * cptr, pthread_mutex_t *mptr, const struct timespec *abstime);如果时间到了,条件变量还没有为真,仍然返回,返回值为ETIME。
使用条件变量可以以原子方式阻塞线程,直到某个特定条件为真为止。条件变量始终与互斥锁一起使用。对条件的测试是在互斥锁(互斥)的保护下进行的。
如果条件为假,线程通常会基于条件变量阻塞,并以原子方式释放等待条件变化的互斥锁。如果另一个线程更改了条件,该线程可能会向相关的条件变量发出信号,从而使一个或多个等待的线程执行以下操作:
在以下情况下,条件变量可用于在进程之间同步线程:
当pthread_cond_timedwait()被调用时,调用线程必须已经锁住了mutex。函数pthread_cond_timedwait()会对mutex进行【解锁和执行对条件的等待】(原子操作)。这里的原子意味着:解锁和执行条件的等待是原则的,一体的。(In this case, atomically means with respect to the mutex and the condition variable and other access by threads to those objects through the pthread condition variable interfaces.)
如果等待条件满足或超时,或线程被取消,调用线程需要在线程继续执行前先自动锁住mutex,如果没有锁住mutex,产生EPERM错误。即,该函数返回时,mutex已经被调用线程锁住。
即:
pthread_cond_t条件变量必须与互斥锁一起使用,调用pthread_cond_wait系列时,其会自动解锁mutex并执行条件等待(原子操作),而在条件满足或超时等其他原因线程可以继续执行时,会在线程执行前先锁住mutex然后该函数才返回。
在线程等待条件变量时,mutex实际上是处于解锁状态的
当然了,比较悲剧的是,若没锁住则会返回EPERM
下面摘一下别人的例子,我试着编译运行了下,确实如此。。。
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
|
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
pthread_t
thread
;
pthread_cond_t cond;
pthread_mutex_t mutex;
int
flag = 1;
void
* thr_fn(
void
* arg) {
struct
timeval now;
struct
timespec outtime;
pthread_mutex_lock(&mutex);
while
(flag) {
printf
(
".\n"
);
gettimeofday(&now, NULL);
outtime.tv_sec = now.tv_sec + 5;
outtime.tv_nsec = now.tv_usec * 1000;
pthread_cond_timedwait(&cond, &mutex, &outtime);
}
pthread_mutex_unlock(&mutex);
printf
(
"thread exit\n"
);
}
int
main() {
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
if
(0 != pthread_create(&
thread
, NULL, thr_fn, NULL)) {
printf
(
"error when create pthread,%d\n"
,
errno
);
return
1;
}
char
c ;
while
((c =
getchar
()) !=
'q'
);
printf
(
"Now terminate the thread!\n"
);
flag = 0;
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
printf
(
"Wait for thread to exit\n"
);
pthread_join(
thread
, NULL);
printf
(
"Bye\n"
);
return
0;
}
|