一、概述
典型的Unix和Linux进程可以看成一个控制的线程,这个进程在同一时刻只做一件事情;
当Unix和Linux进程有了多个控制线程之后,进程在同一时刻就不只做一件事情,每个线程都有各自处理的任务;
进程在程序运行的过程,是系统分配资源的基本单位,在线程设计的系统中,进程本身并不是基本运行的单位,而是线程的容器;
线程是操作系统能够进行运算调度的最小单位;
一个进程中可以并发多个线程,每条线程并行执行不同的任务。
二、创建子线程
API原型
SYNOPSIS
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
API的参数
pthread_t *thread:子线程入口地址,创建一个pthread_t类型的子线程;
const pthread_attr_t *attr:线程的属性,一般使用NULL,具体可以在man手册查看;
void *(*start_routine) (void *):子线程入口函数,注意函数的类型;
void *arg:子函数的入口参数;
返回值:成功返回0,错误返回-1,并设置errno。
API的demo_1(创建子线程,并获取线程ID)
#include <stdio.h>
#include <pthread.h>
void *fun1(void *arg){
printf("task : thread is create\n");
printf("task : %ld \n",(unsigned long)pthread_self());
printf("task : param is %d \n",*((int *)arg));
}
int main()
{
pthread_t task;
int ret;
int param = 100;
ret = pthread_create(&task, NULL, fun1, (void *)¶m);
//返回值为0时创建成功
if(ret == 0){
printf("main : create success\n");
}
printf("main : %ld\n",(unsigned long)pthread_self());
pthread_join(task, NULL);//等待子线程执行完成退出
return 0;
}
demo_1的运行
API的demo_2(创建子线程,执行完子线程,并返回一个整数)
#include <stdio.h>
#include <pthread.h>
void *fun1(void *arg){
static int ret = 10; //退出码要使用静态变量
printf("task : thread is create\n");
printf("task : %ld \n",(unsigned long)pthread_self());
printf("task : param is %d \n",*((int *)arg));
pthread_exit((void *)&ret);
}
int main()
{
pthread_t task;
int ret;
int param = 100;
int *pret = NULL;
ret = pthread_create(&task, NULL, fun1, (void *)¶m);
//返回值为0时创建成功
if(ret == 0){
printf("main : create success\n");
}
printf("main : %ld\n",(unsigned long)pthread_self());
pthread_join(task, (void **)&pret);//等待子线程执行完成退出
//子线程退出的状态码
printf("main : t1 quit : %d\n",*pret);
return 0;
}
demo_2的运行
API的demo_3(创建子线程,执行完子线程,并返回字符串)
#include <stdio.h>
#include <pthread.h>
void *fun1(void *arg){
static char *p = "task is run out"; //退出码要使用静态变量
printf("task : thread is create\n");
printf("task : %ld \n",(unsigned long)pthread_self());
printf("task : param is %d \n",*((int *)arg));
pthread_exit((void *)p);
}
int main()
{
pthread_t task;
int ret;
int param = 100;
char *pret = NULL;
ret = pthread_create(&task, NULL, fun1, (void *)¶m);
//返回值为0时创建成功
if(ret == 0){
printf("main : create success\n");
}
printf("main : %ld\n",(unsigned long)pthread_self());
pthread_join(task, (void **)&pret);//等待子线程执行完成退出
//子线程退出的状态码
printf("main : t1 quit : %s\n",pret);
return 0;
}
demo_3的运行
三、多个线程共享内存
demo
#include <stdio.h>
#include <pthread.h>
void *fun1(void *arg){
printf("task_1 : thread is create\n");
printf("task_1 : %ld \n",(unsigned long)pthread_self());
}
void *fun2(void *arg){
printf("task_2 : thread is create\n");
printf("task_2 : %ld \n",(unsigned long)pthread_self());
}
int main()
{
pthread_t task_1;
pthread_t task_2;
int ret;
int param = 100;
ret = pthread_create(&task_1, NULL, fun1, (void *)¶m);
if(ret == 0){
printf("main : task_1 create success\n");
}
ret = pthread_create(&task_2, NULL, fun2, (void *)¶m);
if(ret == 0){
printf("main : task_2 create success\n");
}
printf("main : %ld\n",(unsigned long)pthread_self());
while(1);//防止主线程退出
return 0;
}
demo的运行
从运行结果来看,并不存在先执行线程1,再执行线程2,这里两个线程为同等优先级,两个线程会相互争夺CPU的使用权;
四、互斥量限制共享资源
API原型
SYNOPSIS
#include <pthread.h>
//创建锁
int pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutex‐attr);
//销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//上锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
//解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
API参数
pthread_mutex_t *mutex:创建的锁(互斥量),类型为pthread_mutex_t;
const pthread_mutexattr_t *mutex‐attr:锁的属性,当为NULL时,默认为互斥锁;
返回值:都是成功返回0,错误返回-1,设置错误码。
API的demo
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex;
void *fun1(void *arg){
pthread_mutex_lock(&mutex);//上锁
for(int i=0;i<3;i++){
printf("task_1 : thread is create\n");
printf("task_1 : %ld \n",(unsigned long)pthread_self());
}
pthread_mutex_unlock(&mutex);//解锁
}
void *fun2(void *arg){
usleep(1);
printf("task_2 : thread is create\n");
printf("task_2 : %ld \n",(unsigned long)pthread_self());
}
int main()
{
pthread_t task_1;
pthread_t task_2;
int ret;
int param = 100;
pthread_mutex_init(&mutex, NULL); //创建锁
ret = pthread_create(&task_1, NULL, fun1, (void *)¶m);
if(ret == 0){
printf("main : task_1 create success\n");
}
ret = pthread_create(&task_2, NULL, fun2, (void *)¶m);
if(ret == 0){
printf("main : task_2 create success\n");
}
printf("main : %ld\n",(unsigned long)pthread_self());
pthread_join(task_1,NULL);
pthread_join(task_2,NULL);
pthread_mutex_destroy(&mutex); //销毁锁
return 0;
}
demo的运行
在task_1上锁之后,会先执行完线程1里面的内容,不被打断
五、死锁
死锁是相对一个概念,就是两个线程互锁住了,僵持不下;
我们要避免出现死锁,所以在使用锁的时候要格外注意是否出现死锁;
死锁的demo
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex_1;
pthread_mutex_t mutex_2;
void *fun1(void *arg){
pthread_mutex_lock(&mutex_1);//上锁
sleep(1);
pthread_mutex_lock(&mutex_2);
for(int i=0;i<3;i++){
printf("task_1 : thread is create\n");
printf("task_1 : %ld \n",(unsigned long)pthread_self());
}
pthread_mutex_unlock(&mutex_1); //解锁
}
void *fun2(void *arg){
pthread_mutex_lock(&mutex_2);//上锁
sleep(1);
pthread_mutex_lock(&mutex_1);
for(int i=0;i<3;i++){
printf("task_2 : thread is create\n");
printf("task_2 : %ld \n",(unsigned long)pthread_self());
}
pthread_mutex_unlock(&mutex_2);//解锁
}
int main()
{
pthread_t task_1;
pthread_t task_2;
int ret;
int param = 100;
pthread_mutex_init(&mutex_1, NULL); //创建锁1
pthread_mutex_init(&mutex_2, NULL); //创建锁2
ret = pthread_create(&task_1, NULL, fun1, (void *)¶m);
if(ret == 0){
printf("main : task_1 create success\n");
}
ret = pthread_create(&task_2, NULL, fun2, (void *)¶m);
if(ret == 0){
printf("main : task_2 create success\n");
}
printf("main : %ld\n",(unsigned long)pthread_self());
pthread_join(task_1,NULL); //等待线程1
pthread_join(task_2,NULL); //等待线程2
pthread_mutex_destroy(&mutex_1); //销毁锁1
pthread_mutex_destroy(&mutex_2); //销毁锁2
return 0;
}
demo的运行
如上图所示,两个线程被相互锁住,进程卡住运行不了。