一.多线程程序设计
1.线程的创建:pthread_create
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
第一个参数:创建的线程的id,是一个传出参数
第二个参数:线程属性 —> 一般为NULL(控制线程的大小)
第三个参数:线程的工作函数,线程创建成功后,从该函数开始执行
第四个参数:给工作函数传的参数
返回值:成功返回0,失败返回erroe number
2.线程ID获取:pthread_self
pthread_t pthread_self(void);
3.线程结束处理
(1)、调用 pthread_join 回收线程资源(阻塞型,只能回收单个线程)
(2)、使用线程分离,将线程的资源回收工作交给系统(非阻塞型)
(3)、当主线程调用 pthread_exit() 不影响其他线程执行,进程当所有线程都结束以后才退出
注意:线程分离与线程结束时一起使用的
#include <stdio.h>
#include <pthread.h>
// 线程的工作函数
void *worker(void *v)
{
// while (1)
{
printf ("子线程id: %ld\n", pthread_self());
sleep(5);
}
printf ("子线程退出\n");
}
int main()
{
pthread_t thread;
pthread_create(&thread, NULL, worker, NULL);
pthread_detach(thread); // 线程分离
printf("asdsadsa\n");
pthread_exit(NULL); // 主线程结束运行
return 0;
}
主线程运行结束,则进程退出。
全局变量直接作为线程间通信的桥梁。
二.线程同步
(1).信号量
1.创建:sem_init
int sem_init(sem_t *sem, int pshared, unsigned int value);
使用:(一般情况下后两个参数的设定如下)
sem_t sem
sem_init(&sem, 0, 1);
2.控制
int sem_post(sem_t *sem); // v(+1)
int sem_wait(sem_t *sem); // p(-1)
3.销毁
int sem_destroy(sem_t *sem);
4.生产者与消费者模型
产生消息的是生产者,处理消息的是消费者,消费者和生产者通过一个缓冲区进行消息传递。
初始值:空:1 满:0
生产者 | 消费者 |
---|---|
p(空) | p(满) |
v(满) | v(空) |
(2)互斥量(互斥琐)
1.初始化:pthread_mutex_init
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
2.操作函数:
int pthread_mutex_lock(pthread_mutex_t *mutex);//上锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁
3.销毁:pthread_mutex_destroy
int pthread_mutex_destroy(pthread_mutex_t *mutex);
4.生产者与消费者模型
提高效率
生产者 | 消费者 |
---|---|
上锁 | 上锁 |
p(空) | p(满) |
解锁 | 解锁 |
v(满) | v(空) |
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <string.h>
struct msg
{
char *buf[10]; // 缓冲区中的数据
sem_t full; // 控制消费者进入
sem_t empty; // 控制生产者进入
int count; // 资源的个数
}data; // 全局数据
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁
// 生产者工作函数
void *produce(void *v)
{
char *buf[] = {"苹果", "梨", "香蕉", "西瓜", "芒果", "葡萄", "菠萝", "红柚"};
int len = sizeof(buf)/sizeof(buf[0]);
while (1)
{
usleep(100000*(rand()%10+1));
sem_wait(&data.empty); // 生产者只有当缓冲区为空的时候才能进入
pthread_mutex_lock(&mutex);
data.buf[data.count] = buf[rand()%len];
data.count ++;
pthread_mutex_unlock(&mutex);
sem_post(&data.full); // 生产者放入消息以后,通知消费者去处理
}
}
// 消费者工作函数
void *consume(void *v)
{
long num = (long)v;
while (1)
{
usleep(100000*(rand()%10+1));
sem_wait(&data.full); // 消费者只有当缓冲区中有数据的时候才能进入
pthread_mutex_lock(&mutex);
int index = rand() % data.count;
printf ("%ld 号消费者,吃了一个 %s, 剩余个数:%d\n", num, data.buf[index], data.count-1);
data.count--;
char *tmp = data.buf[index];
data.buf[index] = data.buf[data.count];
data.buf[data.count] = tmp;
pthread_mutex_unlock(&mutex);
sem_post(&data.empty); // 消费者处理完数据以后,通知生产者去放数据
}
}
int main(int argc, char **argv)
{
srand((unsigned int)time(NULL));
long i;
pthread_t thread;
for (i = 0; i < 4; i++)
{
pthread_create(&thread, NULL, consume, (void*)(i+1));
pthread_detach(thread);
}
for (i = 0; i < 4; i++)
{
pthread_create(&thread, NULL, produce, NULL);
pthread_detach(thread);
}
sem_init(&data.full, 0, 0);
sem_init(&data.empty, 0, 10);
pthread_exit(NULL);
return 0;
}
(3)条件变量
1.初始化:pthread_cond_init
int pthread_cond_init(pthread_cond_t *cond,const pthread_condattr_t *attr);
2.等待:pthread_cond_wait
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
3.触发:pthread_cond_broadcast
int pthread_cond_broadcast(pthread_cond_t *cond);
4.销毁:pthread_cond_destroy
int pthread_cond_destroy(pthread_cond_t *cond);
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <string.h>
int resource = 0; // 资源
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁
pthread_cond_t cond1; // 条件变量
// 生产者工作函数
void *produce(void *v)
{
while (1)
{
usleep(100000*(rand()%10+1));
pthread_mutex_lock(&mutex);
resource += 2;
pthread_cond_broadcast(&cond1); // 广播
pthread_mutex_unlock(&mutex);
}
}
// 消费者工作函数
void *consume(void *v)
{
while (1)
{
usleep(100000*(rand()%10+1));
pthread_mutex_lock(&mutex);
while (resource <= 0)
{
// 为什么要有循环
// 因为当线程被唤醒的时候,有可能条件还是不满足的,所以还需要判断一次
// 1、当等待的时候,会自动解锁
// 2、当被唤醒的时候,会和其他线程一起抢锁
pthread_cond_wait(&cond1, &mutex); // 等待条件满足
}
resource--;
printf ("消费,剩余个数:%d\n", resource);
pthread_mutex_unlock(&mutex);
}
}
int main(int argc, char **argv)
{
srand((unsigned int)time(NULL));
long i;
pthread_t thread;
for (i = 0; i < 4; i++)
{
pthread_create(&thread, NULL, consume, (void*)(i+1));
pthread_detach(thread);
}
// for (i = 0; i < 4; i++)
//{
pthread_create(&thread, NULL, produce, NULL);
pthread_detach(thread);
//}
pthread_cond_init(&cond1, NULL);
pthread_exit(NULL);
return 0;
}