一、多线程,属于同一个进程
只有局部访问全局,没有全局访问局部,进程中的全局变量可以被同一进程中的多线程访问,
1、了解多线程:
解决多任务实现;
历史上Unix服务器不支持多线程,通过多进程(select模型来解决!)。
在Unix、linux实现多线程两种方式:
@1、内核支持多线程,内核重启来支持多线程
@2、使用进程的编程技巧封装进程,从而实现多线程,轻量级多线程,基于函数封装实现(API实现):libpthead.so(线程库);
多线程库:
libpthread.so -lpthread(编译多线程时需加上);头文件:#include<pthread.h>
编译方法:gcc -g pthread1.c -o pthread -lpthread
2、创建多线程
线程代码:回调函数实现,
线程ID:ID由进程管理,pthread_t
创建、运行线程:pthread_create
int pthread_create(pthread_t *thread, //线程id
const pthread_attr_t *attr,//线程属性
void *(*start_routine) (void *),//线程代码
void *arg);//传递线程代码的数据
主进程结束后,里面的线程全结束!
进程问题,主进程结束,子进程不一定结束,但是,主进程里面的线程全结束。
pthread_join(pthread_t pid,//线程ID
void **retval //线程返回值);///等待子线程结束
创建子线程后,主线程继续完成系统分配
子线程结束就是线程函数饭后。
子线程与主线程有同等的的优先级,默认情况是同等的优先级。
例子1:
#include <pthread.h>
#include <stdio.h>
void *run(void *data)
{
while(1)
{
printf("pthread!\n");
sleep(1);
sched_yield();
}
}
int main()
{
pthread_t pid;
pthread_create(&pid,0,run,0);
while(1)
{
sleep(1);
printf("main pthread\n");
sched_yield();
}
pthread_join(pid,(void**)0);
sleep(2);
return 0;
}
例子2.主线程+2个子线程
#include <pthread.h>
#include <stdio.h>
void *run(void *data)
{
while(1)
{
printf("pthread1 !\n");
sleep(1);
sched_yield();
}
}
void *run2(void *data)
{
while(1)
{
printf("pthread2 !\n");
sleep(1);
sched_yield();
}
}
int main()
{
pthread_t pid,pid2;
pthread_create(&pid,0,run,0);
pthread_create(&pid2,0,run2,0);
while(1)
{
sleep(1);
printf("main pthread\n");
sched_yield();
}
pthread_join(pid,(void**)0);
pthread_join(pid2,(void**)0);
// sleep(2);
return 0;
}
/
gbd 调试:
run, br x(加断点),whatis a(a是什么类型),等等
/
3、线程的基本控制
线程的状体:ready->runny->deady
sleep()/pause()
3.1 结束线程的方法:第一种:可以在子线程的方式中void *run2(void *data),加上 return 返回值。
第二种: void pthread_exit(void *retval);
方法:
void *run(void *data)
{
while(1)
{
printf("pthread1 !\n");
sleep(1);
sched_yield();
// return "hang";//第一种
pthread_exit("dian");//第二种
}
}
3.2 线程的开始:
void *run(void *data)
{
while(1)
{
printf("pthread1 ,%s!\n",data);
sleep(1);
sched_yield();
// return "hang";
pthread_exit("dian");
}
}
int main()
{
pthread_t pid,pid2;
pthread_create(&pid,0,run,“data”);//"data"数据就可以传递到子线程的run方法中,
pthread_create(&pid2,0,run2,0);
while(1)
{
sleep(1);
printf("main pthread\n");
sched_yield();
}
pthread_join(pid,(void**)0);
pthread_join(pid2,(void**)0);
// sleep(2);
return 0;
}
4、多线程问题:共享数据容易发生问题,多线程抢数据,
5、多线程问题的解决:
5.1互斥锁/互斥量 mutex
定义互斥量:pthread_mutex_t
初始化互斥量:pthread_mutex_init
互斥量操作:置0:pthread_mutex_lock;
判断互斥量0:阻塞,3:置0后再返回!
置1:pthread_mutex_unlock;;置1后返回!
释放互斥量:pthread_mutex_destroy
例子:互斥量的方法:
#include <pthread.h>
#include <stdio.h>
//定义互斥
pthread_mutex_t m ;
int a = 0, b = 0;
void destroy()
{
//加锁
pthread_mutex_lock(&m);
a++;
b++;
// pthread_mutex_unlock(&m);//在这个地方释放的锁的话,有输出
if(a!=b)
{
printf("%d!=%d \n",a,b);
a = b =0;
}
//开锁
pthread_mutex_unlock(&m);//锁在这个地方释放的话,没有输出
}
void *r1(void *data)
{
while(1)
{
destroy();
}
}
void *r2(void *data)
{
while(1)
{
destroy();
}
}
int main()
{
pthread_t pid1,pid2;
//初始化
pthread_mutex_init(&m,0);
pthread_create(&pid1,0,r1,0);
pthread_create(&pid2,0,r2,0);
pthread_join(pid1,(void**)0);
pthread_join(pid2,(void**)0);
return 0;
}
/
总结:
mute锁之间的变量,指的是:同一个时间片内,只允许一个线程访问!,不代表值不变。
在lock和unlock之间,调用pthread_exit, pthread_cancel 其他线程将永久死锁!
/克服上面一些问题方法:
pthread_cleanup_push
pthread_cleanup_pop这对函数作用类似于atexit(进程使用),但是这两个函数并不是函数,而是宏!这两个必须成对使用!!!!
void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);
例子:
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t m;
void handle(void *d)
{
printf("tuichu!");
}
void *runeven(void *d)
{
int i = 0;
for(i = 0;;i+=2)
{
pthread_mutex_lock(&m);
pthread_cleanup_push(handle,0);
printf("even:%d\n",i);
sleep(1);
pthread_cleanup_pop(0);
pthread_mutex_unlock(&m);
}
}
void *runodd(void *d)
{
int i = 0;
for(i = 1;;i+=2)
{
pthread_mutex_lock(&m);
pthread_cleanup_push(handle,0);
printf("odd:%d\n",i);
pthread_cleanup_pop(0);
pthread_mutex_unlock(&m);
}
}
int main()
{
pthread_t p1,p2;
pthread_mutex_init(&m,0);
pthread_create(&p1,0,runodd,0);
pthread_create(&p2,0,runeven,0);
sleep(3);
pthread_cancel(p2);
pthread_join(p1,(void*)0);
pthread_join(p2,(void*)0);
pthread_mutex_destroy(&m);
return 0;
}
///
pthread_cleanup_pop和pthread_cleanup_push要在pthread_mutex_lock内
//