1、什么是线程
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属于一个进程的其他的线程共享进程拥有的全部资源。
2、线程创建
头文件:#include <pthread.h>
函数原型:int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
参数说明:thread:指向pthread_t类型的指针,用于引用新创建的线程。
attr:用于设置线程的属性,一般不需要特殊的属性,所以可以简单地设置为NULL。
*(*start_routine)(void *):传递新线程所要执行的函数地址。
arg:新线程所要执行的函数的参数。
调用如果成功,则返回值是0,如果失败则返回错误代码。
#include <stdio.h>
#include <pthread.h>
void *pthread_run(void* a)
{
while(1)
{
sleep(1);
printf("pthread 函数\n");
}
}
int main()
{
pthread_t pthread_id;
int ret = pthread_create(&pthread_id,NULL,pthread_run, NULL);
if(ret != 0)
{
perror("pthread_create");
return -1;
}
while(1)
{
sleep(1);
printf("main 函数\n");
}
return 0;
}
3、线程的参数传递
#include <stdio.h>
#include <pthread.h>
struct data
{
int a;
int b;
};
void *pthread_run(void* a)
{
struct data *value = (struct data *)a;
printf("a = %d,b = %d\n",value->a,value->b);
int result = value->a + value->b;
pthread_exit((void *)result);
}
int main()
{
struct data value;
value.a = 10;
value.b = 20;
pthread_t pthread_id;
int ret = pthread_create(&pthread_id,NULL,pthread_run, (void*)&value);
if(ret != 0)
{
perror("pthread_create");
return -1;
}
sleep(1);
int result;
pthread_join(pthread_id, (void **)&result);
printf("a + b = %d\n",result);
return 0;
}
4、信号量
生产者与消费者模型
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#include <string.h>
// 信号量和缓冲区
struct data
{
sem_t empty; // 用来控制生产者,只有缓冲区为空,生产者才可以生产消息
sem_t full; // 用来控制消费者,只有缓冲区有数据,才可以消费
char buf[32]; // 消息缓冲区
};
struct data msg;
// 生产者线程工作函数
void *Produce(void *v)
{
char *buf[] = {"苹果", "梨", "香蕉", "榴莲", "橙子", "西瓜", "芒果", "火龙果"};
while (1)
{
// 只有当缓冲区空才能进,生产消息
sem_wait(&msg.empty);
strcpy(msg.buf, buf[rand()%8]);
printf ("放了一个水果: %s\n", msg.buf);
int time = rand() % 100 + 1;
usleep(time*10000);
// 生产完了,通知消费者进行消费
sem_post(&msg.full);
}
}
// 消费者线程工作函数
void *Consum(void *v)
{
char buf[32];
while (1)
{
// 只有当缓冲区不为空才能进,消费消息
sem_wait(&msg.full);
strcpy(buf, msg.buf);
printf ("吃了一个 %s\n", buf);
int time = rand() % 100 + 1;
usleep(time*10000);
// 消费完了,通知生产则会进行生产
sem_post(&msg.empty);
}
}
int main()
{
srand ((unsigned int)time(NULL));
// 初始化信号量
sem_init(&msg.empty, 0, 1); // 生产者,一开始要生产消息
sem_init(&msg.full, 0, 0); // 消费者,一开始要不能消费消息
pthread_t produceId;
pthread_t consumId;
// 创建生产者线程
pthread_create(&produceId, NULL, Produce, NULL);
// 创建消费者线程
pthread_create(&consumId, NULL, Consum, NULL);
// 等待线程结束
pthread_join(produceId, NULL);
pthread_join(consumId, NULL);
// 销毁信号量
sem_destroy(&msg.empty);
sem_destroy(&msg.full);
return 0;
}
5、互斥量
生产者与消费者模型改进
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#include <string.h>
#include "SqQueue.h"
// 信号量和缓冲区
struct data
{
sem_t empty; // 用来控制生产者,只有缓冲区为空,生产者才可以生产消息
sem_t full; // 用来控制消费者,只有缓冲区有数据,才可以消费
Queue q; // 缓冲区队列
};
struct data msg;
// 互斥锁
pthread_mutex_t mutex;
int num = 0;
// 生产者线程工作函数
void *Produce(void *v)
{
while (1)
{
int time = rand() % 100 + 1;
usleep(time*10000);
// 只要队列不满 就能生产消息, empty代表当前队列剩余的空间
sem_wait(&msg.empty);
pthread_mutex_lock(&mutex); // 抢锁
num++; // 生产一个消息
// 将消息放入到队列里面
EnQueue (&(msg.q), num);
printf ("生产一条消息\n");
pthread_mutex_unlock(&mutex); // 解锁
// 生产完了,通知消费者进行消费
sem_post(&msg.full);
}
}
// 消费者线程工作函数
void *Consum(void *v)
{
char buf[32];
while (1)
{
int time = rand() % 100 + 1;
usleep(time*10000);
// 只有缓冲区有数据,就能消费消息, full当前队列消息的个数
sem_wait(&msg.full);
pthread_mutex_lock(&mutex); // 抢锁
int num;
DeQueue(&(msg.q), &num); // 去队列里取出一条消息
printf("消费了一条消息: %d\n", num);
pthread_mutex_unlock(&mutex); // 解锁
// 消费完了,通知生产则会进行生产
sem_post(&msg.empty);
}
}
int main()
{
srand ((unsigned int)time(NULL));
// 初始化信号量
sem_init(&msg.empty, 0, 10); // 生产者,一开始要生产 10 条消息
sem_init(&msg.full, 0, 0); // 消费者,一开始要不能消费消息
// 初始化互斥锁
pthread_mutex_init(&mutex, NULL);
// 初始化队列
InitQueue(&(msg.q));
pthread_t produceId;
pthread_t consumId;
int i = 0;
for (i = 0; i < 5; i++)
{
// 创建生产者线程
pthread_create(&produceId, NULL, Produce, NULL);
pthread_detach(produceId);
}
// 创建消费者线程
pthread_create(&consumId, NULL, Consum, NULL);
// 等待线程结束
pthread_join(consumId, NULL);
// 销毁信号量
sem_destroy(&msg.empty);
sem_destroy(&msg.full);
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
return 0;
}
6、线程卖票系统
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
int ticket = 100;
pthread_mutex_t mutex;
void *sell_ticket(void *v)
{
int wind = (int)v;
printf("窗口 %d 开始卖票\n",wind);
while(1)
{
int time = rand() % 101;
usleep(time * 10000);
pthread_mutex_lock(&mutex);
if(ticket == 0)
{
pthread_mutex_unlock(&mutex);
break;
}
printf("窗口 %d 卖出一张票,座位号为:%d\n",wind,ticket);
ticket--;
pthread_mutex_unlock(&mutex);
}
}
int main()
{
srand((unsigned int)time(NULL));
pthread_mutex_init(&mutex, NULL);
int i;
for(i = 1;i < 5;i++)
{
pthread_t pthread_id;
pthread_create(&pthread_id,NULL,sell_ticket, (void*)i);
pthread_detach(pthread_id);
}
pthread_exit(NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
7.条件变量
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#include <string.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
int num = 0;
void *consum(void* v)
{
while(1)
{
int time = rand() % 101;
usleep(time * 10000);
pthread_mutex_lock(&mutex);
while(num == 0)
{
pthread_cond_wait(&cond,&mutex);
}
num--;
printf("消费消息:%d\n",num);
pthread_mutex_unlock(&mutex);
}
}
void *produce(void* v)
{
while(1)
{
int time = rand() % 101;
usleep(time * 10000);
pthread_mutex_lock(&mutex);
num += 2;
printf("生产消息\n");
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
}
}
int main()
{
srand((unsigned int)time(NULL));
//初始化互斥量
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond,NULL);
//创建线程
pthread_t produce_id;
pthread_t consum_id;
pthread_create(&produce_id,NULL,produce, NULL);
pthread_create(&consum_id,NULL,consum, NULL);
//等待线程结束
pthread_join(produce_id,NULL);
pthread_join(consum_id,NULL);
pthread_cond_destroy(&cond);
//销毁互斥量
pthread_mutex_destroy(&mutex);
return 0;
}