一、线程简介
线程是一个进程内的基本调度单位,好比轻量级的进程。
多个线程在一个进程的共享内存空间中并发执行,它们共享一个进程的资源,如文件描述符和信号处理等,大大减少了上下文的开销。 运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而 且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。
总的说来, 一个进程的开销大约是一个线程开销的 30 倍左右。 不同进程具有独立的数据空间,其数据的传递只能通过通信的方式进行,费时且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,不仅快捷,而且方便。
使用多线程能带来更方便的通信机制。 多线程程序作为一种多任务、并发的工作方式,有以下几大优点:
(1) 提高应用程序响应;
(2)使多 CPU 系统更加有效;
(3)改善程序结构。
二、线程API
Linux 中的 pthread 库提供了大量的 API 函数,为用户编写多线程应用程序提供丰富支持。
1.线程创建
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
// 返回:若成功返回0,否则返回错误编号
第一个参数为指向线程标识符的指针;
第二个参数用来设置线程属性,设为空指针时将生成默认属性的线程;
第三个参数是线程运行函数的起始地址;
最后一个参数是运行函数的参数,不需要参数时最后一个参数设为空指针 NULL。
当创建线程成功时,函数返回 0,若不为 0 则说明创建线程失败。 创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。
2.线程等待
#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
函数 pthread_join 用来等待一个线程的结束,相当于进程中的 wait()系统调用。
pthread_join()将当前线程挂起,等待线程结束。这个函数是一个线程阻塞函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待 线程的资源才被收回。
第一个参数为被等待的线程标识符;
第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。
3.线程退出
#include <pthread.h>
int pthread_exit(void *rval_ptr);
一个线程的结束有两种途径,一种是函数结束了,调用它的线程也就结束 了;另一种方式是通过函数 pthread_exit 来实现。
唯一的参数是函数的返回代码,也就是 pthread_exit()调用者线程的返回值, 可由 pthread_join 来检索获取。只要 pthread_join 中的第二个参数rval_ptr不是 NULL,这个值将被传递给 rval_ptr。
4. 线程脱离
pthread_detach函数把指定的线程转变为脱离状态。
#include <pthread.h>
int pthread_detach(pthread_t thread);
若成功返回0,否则返回错误编号,本函数通常由想让自己脱离的线程使用,就如以下语句:
pthread_detach(pthread_self());
5.线程ID获取及比较
#include <pthread.h>
pthread_t pthread_self(void);
返回:调用线程的ID
三、互斥锁机制API
1.创建及销毁互斥锁
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
返回:若成功返回0,否则返回错误编号
要用默认的属性初始化互斥量,只需把attr设置为NULL。
2. 加锁及解锁
#include <pthread.h>
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,否则返回错误编号
四、条件变量API
1.创建及销毁条件变量
#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);
除非需要创建一个非默认属性的条件变量,否则pthread_cont_init函数的attr参数可以设置为NULL。
2. 等待
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, cond struct timespec *restrict timeout);
3. 触发
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t cond);
int pthread_cond_broadcast(pthread_cond_t cond);
五、示例
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
static a = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;
void *fun1(void *arg)
{
// static char *p = "this is t1 out\n";
printf("t1: %ld is create\n",(unsigned long)pthread_self());
printf("t1:value is %d\n",*((int *)arg));
int cnt = 1;
while(1){
pthread_cond_wait(&cond, &mutex);
printf("t1 run=====================\n");
printf("t1 :%d\n",a++);
a = 0;
if(cnt++ == 5){
exit(0);
}
sleep(1);
}
// pthread_exit((void *)p);
}
void *fun2(void *arg)
{
printf("t2: %ld is create\n",(unsigned long)pthread_self());
printf("t2:value is %d\n",*((int *)arg));
while(1){
pthread_mutex_lock(&mutex);
printf("t2 :%d\n",a++);
if(a == 3)
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main()
{
pthread_t t1,t2;
int ret1,ret2;
int pro = 100;
char *p;
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond, NULL);
ret1 = pthread_create(&t1,NULL,fun1,(void *)&pro);
ret2 = pthread_create(&t2,NULL,fun2,(void *)&pro);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
// printf("main: ti quit : %s\n",p);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}