多线程编程

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值