本内容包括:多线程编程实例,互斥量及条件变量使用
多线程编程:建立一个pthread_t的变量,创建一个void *fun(void *var)的函数,创建属性,不建议如此设计,使用pthread_creat(pthread_t *tid, pthread_attr_t *attr, void *(*fun)(void *var), void *var);
pthread_key_t 表示在线程内的私有变量,在该线程内不同函数可用。使用pthread_getspecific(key)pthread_getspecific 返回 pkey 中对应于 key 的指针, pthread_setspecific (key, void *value)将 pkey 中对应于 key 的指针设置为 value。
pthread_detach(pthread_t tid):类似于将tid的线程脱离终端。如果线程不设置为detach,在线程退出时是不会释放资源的。
线 程 状 态 的 可 能 取 值 为 PTHREAD_CREATE_JOINABLE 和 PTHREAD_CREATE_DETACHED 。 pthread_attr_getdetachstate 函 数 用 来 查 看 一 个 属 性 对 象 中 的 线 程 状 态 , 而 pthread_attr_setdetachstate 函数用来设置一个属性对象中的线程状态。 这两个函数的形式为: int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate); int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); 如果成功,这些函数都返回 0。如果不成功,他们就返回一个非零的错误码。 如前所述,可以通过调用 pthread_detach 函数来分离一个线程,现在也可以通过先设置属 性对象的线程状态为 PTHREAD_CREATE_DETACHED,并在创建线程时传递这个属性对象,使线 程处于分离状态。被分离的线程是不能用 pthread_join 来等待的。默认情况下,线程是可 接合的。
pthread_key_delete:清除tsl,不清除函数.
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <malloc.h> #include <string.h> pthread_key_t key; void set(char *str){ char *s = (char *)pthread_getspecific(key); strncpy(s, str, 100); printf("%d set str %s\n", (int)pthread_self(), s); } void get(){ char *s = (char *)pthread_getspecific(key); printf("%d get str %s\n", (int)pthread_self(), s); } void *fun1(void *str){ pthread_setspecific(key, malloc(100)); set((char *)str); get(); } void *fun2(void *str){ pthread_setspecific(key, malloc(100)); set("thread2"); get(); } void *fun3(void *str){ pthread_setspecific(key, malloc(10)); get(); } void destroy(void *var){ free(var); printf("free memory\n"); } int main(){ pthread_attr_t attr = {0}; pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_t tid1, tid2, tid3; pthread_key_create(&key, destroy); pthread_create(&tid1, NULL, &fun1, "thread1"); pthread_create(&tid2, NULL, &fun2, NULL); pthread_create(&tid3, &attr, &fun3, NULL); pthread_join(tid2, NULL); pthread_join(tid1, NULL); pthread_key_delete(key); pthread_exit(NULL); return 0; }
/* 定义mutex POSIX 使用 pthread_mutex_t 类型的变量来表示互斥量。
程序在使用 pthread_mutex_t 变量
之 前 , 必 须 对 其 进 行 初 始 化 。 对 于 静 态 分 配 的 pthread_mutex_t 变 量 ,
只 要 将PTHREAD_MUTEX_INITIALIZER 赋给这个变量即可,对于动态创建或不使用默认属性的互斥量
来说,就要调用 pthread_mutex_init 函数来对其进行初始化。pthread_mutex_init 函数的
形式为:
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t
*restrict attr);
参数 mutex 是指向要初始化的互斥量的指针,参数 attr 是设定互斥量属性的变量的指针,
如果为 NULL,则使互斥量拥有默认属性。
定义信号量
POSIX 用 pthread_cond_t 类型的变量来表示条件变量。程序必须在使用 pthread_cond_t 变
量之前对其进行初始化。对那些静态分配的、使用默认属性的 pthread_cond_t 变量来说,
可以直接将 PTHREAD_COND_INITIALIZER 赋给变量就可以完成初始化。对那些动态分配的或
不使用默认属性的变量来说,
就要调用 pthread_cond_init 函数来执行初始化。
该函数的形
式为:
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t
*restrict attr);
参数 attr 是一个条件变量属性对象,如果将 NULL 传递给 attr,则初始化一个具有默认属
性的条件变量,否则,就要用与线程属性对象类似的方式,先创建一个条件变量属性对象,
再设置它。如果成功,pthread_cond_init 返回 0,如果不成功,pthread_cond_init 就返
回一个非零的错误码。下表列出了 pthread_cond_init 的错误码和原因:
错误 原因
EAGAIN 系统缺乏初始化*mutex 所需的非内存资源
ENOMEM 系统缺乏初始化*mutex 所需的内存资源
加锁和解缩
POSIX 中 有 两 个 可 以 用 来 获 取 互 斥 量 的 函 数 , pthread_mutex_lock 和
pthread_mutex_trylock。
pthread_mutex_lock 函数会使调用这个函数的线程一直阻塞到互
斥量可用为止,而 pthread_mutex_trylock 会立即返回,如果互斥量空闲,那么调用这个函
数的线程将获得互斥量,否则函数将返回 EBUSY。pthread_mutex_unlock 用于释放互斥量。
这三个函数的形式为:
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
如果成功,这些函数就返回 0,如果不成功,这些函数就返回一个非零的错误码。
通知和唤醒条件变量
条件变量是与断言或条件测试一同调用的,条件变量这个名称就是从这个事实中引申出来
的。通常,线程会对一个断言进行测试,如果测试失败,就调用 pthread_cond_wait。函数
pthread_cond_timedwait 可以用来等待一段有限的时间。
这两个函数的第一个参数 cond 是
一个指向条件变量的指针,
第二个参数 mutex 是一个指向互斥量的指针。
线程在调用等待条
件变量的函数之前,应该拥有这个互斥量。当线程被放置在条件变量的等待队列中时,等待
操作会释放这个互斥量。pthread_cond_timedwait 函数的第三个参数是一个指向返回时间
的指针,如果条件变量信号没有在此之前出现的话,线程就在这个时间返回。注意,这个值
表示的是绝对时间,而不是时间间隔。这两个函数的形式为:
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t
*restrict mutex, const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict
mutex);
如果成功,这两个函数返回 0。如果不成功,它们返回一个非零的错误码。如果 abstime 指
定的时间已经到期了,pthread_cond_timedwait 就返回 ETIMEDOUT。
当另一个线程修改了可能会使断言成真的变量时,
它应该唤醒一个或多个在等待断言成真的
线程。pthread_cond_signal 函数只唤醒一个阻塞在 cond 指向的条件变量上的线程。
pthread_cond_broadcast 函数解除所有阻塞在 cond 指向的条件变量上的线程。这两个函数
的形式为:
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
如果成功,这两个函数返回 0,如果不成功,它们返回一个非零的错误码。等待条件变量的
线程在被唤醒后会等待对应的互斥量,在它获得了互斥量之后,它才会被复原成就绪状态。
销毁互斥量和条件变量
当不再使用已经定义了的互斥量时,
需要将互斥量销毁。
函数 pthread_mutex_destory 用于
销毁互斥量。它的形式为:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
参数 mutex 指向要销毁的互斥量。如果成功,函数返回 0,如果不成功,函数返回一个非零
的错误码。
可以用 pthread_mutex_init 重新初始化被销毁的互斥量。
int pthread_cond_destroy(pthread_cond_t *cond);
如果成功,pthread_cond_destroy 就返回 0。如果不成功,它就返回一个非零的错误码
*/
/*
先互斥,条件满足时,再操作,当满足时,唤醒条件变量
互斥,条件不满足时,等条件变量
*/
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
int data;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void *fun(void *var){
while(1){
pthread_mutex_lock(&mutex);
if(data < 10){
data ++;
printf("data is %d\n", data);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
else{
pthread_mutex_unlock(&mutex);
break;
}
}
return NULL;
}
int main(){
data = 0;
pthread_t tid;
pthread_create(&tid, NULL, &fun, NULL);
pthread_mutex_lock(&mutex);
while(data < 5){
pthread_cond_wait(&cond, &mutex);
}
printf("in the main thread data is %d \n", data);
pthread_mutex_unlock(&mutex);
pthread_join(tid, NULL);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
return 0;
}