线程: 线程是进程创建的,有了进程为什么还要线程呢,和进程相比较,线程是一个十分节俭的多任务操作方式,运行于一个进程中的多个线程,他们之间使用相同的地址空间,而且线程之间批次切换事件所需的时间远远小于进程之间切换所需要的时间。
如果CPU是多核的那么线程之间就是同时的工作,但是如果CPU是单核的那么就只能一个一个来了。但是一个核,对于线程来说,线程也是有意义的,如果一个线程需要数据,我们就可以让其他的线程来执行,不至于让CPU剥夺进程使用CPU的使用权。
线程的好处:
1.线程比进程节俭,线程消耗的是进程的资源,内核不需为线程分配资源,减少了内核的干预。
2.使用多核CPU系统多线程可以使用的更高效。
3.可以改善程序结构
线程是如何工作:
开始需要程序运行,就会产生进程,然后开始创建线程
pthread_create() 函数是创建线程
线程创建成功就生成一个工作线程,创建线程的之前那个还要继续往下执行,那个是主线程。
第一个参数是线程的id,是指针,是一个输出参数,与fork()不同,fork()返回进程的id。第二个参数是线程的属性,一般情况下,是NULL。第三个参数是一个指向函数的指针,赋值就写函数名(线程函数),其中括号里面的参数可以是void也可以是void*,第四个参数是主线程传的值,给线程函数使用的,也可以不传值,填NULL;
一个子线程的结束,进程不会结束,子线程结束用pthread_exit(),线程的任务通过线程函数来实现,如果不用pthread_exit也可以使用线程函数中的return语句,或者线程函数中最后一个 }也是表示线程函数结束。
线程的结束方式
1.线程从启动进程中返回
2.线程可以被另一个进程终止
3.线程自己调用pthread_exit()函数。
pthread_join() 是主线程等待,只能等待一个子线程
子线程不能随意使用exit(-1);没有带pthread。exit(-1)是结束进程的
pthread_self是获取自己的线程id
pthread_cancel是取消线程。
线程同步
多个线程在共同使用共享资源,这样就会产生竞争,竞争就会产生冲突,
如何解决呢?
1.互斥锁 (保证对资源使用权益是独占的)
2.信号灯
3.条件变量
互斥锁
一个线程在获取互斥锁之后就独占这个资源,其他线程不可以获得这个互斥锁,就只能阻塞等待。
使用互斥所的使用步骤:
1.创建互斥锁 互斥所不能定义在函数里,要定义成全局
pthread_mutex_t 这是一个类型,用这个类型定义变量,变量定义好, 互斥所就创建了。
2.初始化:
静态初始化:
把PTHREAD_MUTEX_INITIALIZER给刚刚创建的变量名。,初始化就好了。
动态初始化
需要调用pthread_mutex_int(),进行初始化。
第一个参数:初始化那个互斥锁。
第二个参数:指定互斥锁属性,一般情况是NULL
属性有四种
一是普通锁 PTHREAD_MUTEX_TIMED_NP
相当于NULL:表示当一个线程通过这个普通锁争取到资源,其他线程形成队列等待。一个线程只能锁一次。
二是嵌套锁
允许同一个线程对共享资源上两次或以上的锁。不允许不同线程来锁。
三是检错锁 PTHREAD_MUTEX_RECURSIVE_NP
不允许同一个资源锁多次。
四是适应锁 PTHREAD_MUTEX_ADAPTIVE_NP
等待解锁后重新竞争
3.上锁
4.处理函数
5.解锁
6.销毁
条件变量 就是解决死锁的
1.创建
2.初始化
3.条件变量撤销
4.条件变量等待
#include <stdio.h>
#include <pthread.h> //线程头文件
#define BUFFER_SIZE 16 //货架满
#define OVER -1 //生产者不在放东西了
//共享资源 货架 互斥锁 条件变量
struct product
{
int buffer[BUFFER_SIZE]; //货架
pthread_mutex_t lock; //互斥锁
pthread_cond_t notfull; //不满
pthread_cond_t notempty; //不空
int readpos,writepos; //个数
};
struct product buf;
void init(struct product *b)
{
//动态初始化
pthread_mutex_init(&b->lock,NULL); //初始化互斥锁
pthread_cond_init(&b->notfull,NULL); //初始化条件变量
pthread_cond_init(&b->notempty,NULL);
b->readpos = b->writepos = 0;
}
void put(struct product *b, int data)
{
//放东西第一步上锁
pthread_mutex_lock(&b->lock);
//放东西之前判断是否满
if((b->writepos + 1) % BUFFER_SIZE == b->readpos)
{
pthread_cond_wait(&b->notfull, &b->lock);
}
b->buffer[b->writepos] = data; //不满就往上放
b->writepos++;
if(b->writepos >= BUFFER_SIZE)
{
b->writepos = 0;
}
pthread_cond_signal(&b->notempty); //不空了,发信号
//解锁
pthread_mutex_unlock(&b->lock);
}
int get(struct product *b)
{
int data;
//上锁
pthread_mutex_lock(&b->lock);
//买东西是否为空
if(b->readpos == b->writepos)
{
pthread_cond_wait(&b->notempty, &b->lock); //等待,有了就继续执行
}
data = b->buffer[b->readpos];
b->readpos = (b->readpos + 1) % BUFFER_SIZE; //拿完了不满,就通知上货
//发信号
pthread_cond_signal(&b->notfull); //不满
pthread_mutex_unlock(&b->lock);
return data;
}
//消费者买东西
void *customer(void)
{
int d; //计数,拿了货架上几个
while(1)
{
d = get(&buf); //有就买
if(OVER == d) //东西卖完了
{
break;
}
else
{
printf("%d-------> \n",d);
}
}
return NULL;
}
//生产者放东西
void *producer(void)
{
int n;
for(n = 0; n < 20; n++)
{
printf("%d--------->\n",n+1); //指示
put(&buf,n+1);
}
put(&buf,OVER);//告诉消费者放完了。
//return NULL;
}
int main()
{
//定义线程变量
pthread_t th_p, th_c; //生产者和消费者
//初始化 都要初始化
init(&buf);
//创建线程
pthread_create(&th_p, NULL,(void *) producer, NULL); //生产者线程
pthread_create(&th_c, NULL,(void *)customer, NULL); //消费者线程
//主线程等待
pthread_join(th_p, NULL);
pthread_join(th_c, NULL);
return 0;
}