Linux——线程同步
来源:互联网 发布:mac怎么下载穿越火线 编辑:程序博客网 时间:2024/06/16 02:16
一.多线程
1.了解多线程
解决多任务实现。
历史上Unix服务器不支持多线程
Unix/Linux上实现多线程有两种方式:
内核支持多线程
使用进程的编程技巧封装进程实现多线程:轻量级多线程
多线程的库:
libpthread.so -lpthread
pthread.h
2.创建多线程
2.1.代码?由回调函数实现
2.2.线程ID?pthread_t
2.3.运行线程?
pthread_create
int pthread_create(
pthread_t *th,//返回进程ID
const pthread_attr_t *attr,//线程属性,为NULL/0,使用进程的默认属性
void*(*run)(void*),//线程代码
结论:
1.主程序(主线程)结束所有子线程就结束
解决办法:等待子线程结束
sleep/pause
int pthread_join(
pthread_t tid,//等待子线程结束
void **re);//子线程结束的返回值
2.创建子线程后,主线程继续完成系统分配时间片。
3.子线程结束就是线程函数返回。
作业:
写一个程序创建两个子线程
3.线程的基本控制
线程的状态:
ready->runny->deady
|
sleep/pause
结束线程?
内部自动结束:(建议)
return 返回值;(在线程函数中使用)
void pthread_exit(void*);(在任何线程代码中使用)
外部结束一个线程.
pthread_cancel(pthread_t);
线程开始
4.多线程的问题
互斥锁/互斥量 mutex
1.定义互斥量pthread_mutex_t
2.初始化互斥量 1 pthread_mutex_init
3.互斥量操作 置0 phtread_mutex_lock
判定互斥量0:阻塞
1:置0,返回
置1 pthread_mutex_unlock
置1返回
强烈要求成对使用
4.释放互斥量pthread_mutex_destroy
结论:
互斥量保证锁定的代码一个线程执行,
但不能保证必需执行完!
5.在lock与unlock之间,调用pthread_exit,或者在线程外部调用pthread_cancel,
pthread_cleanup_pop }
这对函数作用类似于atexit,取消线程时回调某个函数
注意:
这不是函数,而是宏.
必须成对使用
二.多线程同步
互斥量/信号/条件量/信号量/读写锁
1.sleep与信号
pthread_kill向指定线程发送信号
signal注册的是进程的信号处理函数.
pthread_kill+sigwait控制进程 如果线程sigwait来不及调用 不处理信号 则发给进程
1.1.定义信号集合
1.2.初始化信号集合
1.3.等待信号
1.4.其他线程发送信号
案例:
sigwait实际处理了信号
如果进程没有处理信号,目标线程也没有sigwait
信号量类似
2.1.定义条件量
2.2.初始化条件量
2.3.等待条件量
2.4.其他线程修改条件量
2.5.释放条件量
案例:
创建两个线程.
一个线程等待信号
一个线程每隔1秒发送信号
pthread_cond_*** 与sigwait都是进程同步控制
pthread_cond_***稳定
练习:
练习:
1.写一个程序:
两个线程写数据到文件.
数据格式:日期时间,线程ID\n
要求:
要求使用互斥, 保证数据正确.
体会使用互斥和不使用互斥的异同.
2.使用curses写一个多线程程序
开启26个线程.每个线程控制一个字母在屏幕上掉落
3.写一个程序:创建两个线程
一个线程负责找素数.
另外一个线程把素数保存到文件
要求:
找到以后,通知另外一个线程保存,停止招素数
线程保存好以后通知素数查找线程继续查找.
目的:
互斥与信号/条件量作用是不同.
1.了解多线程
解决多任务实现。
历史上Unix服务器不支持多线程
Unix/Linux上实现多线程有两种方式:
内核支持多线程
使用进程的编程技巧封装进程实现多线程:轻量级多线程
多线程的库:
libpthread.so -lpthread
pthread.h
2.创建多线程
2.1.代码?由回调函数实现
2.2.线程ID?pthread_t
2.3.运行线程?
pthread_create
int pthread_create(
pthread_t *th,//返回进程ID
const pthread_attr_t *attr,//线程属性,为NULL/0,使用进程的默认属性
void*(*run)(void*),//线程代码
void *data);//传递线程代码的数据
hehe.c
#include <stdio.h>#include <unistd>#include <pthread.h>void* run(void* data){printf("我是线程\n");} main(){pthread_t tid;pthread_create(&tid,0,run,0);//sleep(1);}子进程执行不到 可以用pthread_join()函数等待子线程结束后主线程再执行
结论:
1.主程序(主线程)结束所有子线程就结束
解决办法:等待子线程结束
sleep/pause
int pthread_join(
pthread_t tid,//等待子线程结束
void **re);//子线程结束的返回值
2.创建子线程后,主线程继续完成系统分配时间片。
3.子线程结束就是线程函数返回。
4.子线程与主线程有同等优先级别(你执行一会我执行一会).
createth.c
#include <stdio.h>#include <unistd.h>#include <pthread.h>#include <sched.h>void* run(void* data){while(1){printf("我是线程!%s\n",data);sched_yield();//return "hello";pthread_exit("world");}}main(){pthread_t tid;char *re;pthread_create(&tid,0,run,"Jack");pthread_join(tid,(void**)&re);printf("%s\n",re);}
作业:
写一个程序创建两个子线程
3.线程的基本控制
线程的状态:
ready->runny->deady
|
sleep/pause
结束线程?
内部自动结束:(建议)
return 返回值;(在线程函数中使用)
void pthread_exit(void*);(在任何线程代码中使用)
外部结束一个线程.
pthread_cancel(pthread_t);
线程开始
demo1.c//两个线程一个负责显示随机数 一个显示时间 主线程等待键盘输入退出
#include <curses.h>#include <pthread.h>#include <time.h>#include <math.h>#include <unistd.h>#include <stdlib.h>#include <stdio.h>//全局变量两个窗体WINDOW *wtime,*wnumb;pthread_t thnumb,thtime;pthread_mutex_t m;//线程1:随机数void*runnumb(void *d){int num;while(1){//循环产生7位随机数num=rand()%10000000;pthread_mutex_lock(&m);//显示mvwprintw(wnumb,1,2,"%07d",num);//刷新refresh();wrefresh(wnumb);pthread_mutex_unlock(&m);usleep(1);}return 0;}//线程2:时间void*runtime(void*d){time_t tt;struct tm *t;while(1){//循环取时间tt=time(0);t=localtime(&tt);pthread_mutex_lock(&m);//显示mvwprintw(wtime,1,1,"%02d:%02d:%02d",t->tm_hour,t->tm_min,t->tm_sec);//刷新refresh();wrefresh(wtime);pthread_mutex_unlock(&m);usleep(1);}}main(){//初始化cursesinitscr();curs_set(0);noecho();keypad(stdscr,TRUE);wnumb=derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);wtime=derwin(stdscr,3,10,0,COLS-10);box(wnumb,0,0);box(wtime,0,0);refresh();wrefresh(wnumb);wrefresh(wtime);pthread_mutex_init(&m,0);//2//创建线程1pthread_create(&thnumb,0,runnumb,0);//创建线程2pthread_create(&thtime,0,runtime,0);//等待按键//结束getch();pthread_mutex_destroy(&m);//3delwin(wnumb);delwin(wtime);endwin();}
4.多线程的问题
数据脏
problem.c
#include <stdio.h>#include <pthread.h>//1.pthread_mutex_t m;int a=0,b=0;void *r1(){while(1){pthread_mutex_lock(&m);//判定互斥量0:阻塞 若是1:置0,返回a++;b++;if(a!=b){printf("%d!=%d\n",a,b);a=b=0;}pthread_mutex_unlock(&m);//互斥量置1返回}}void *r2(){while(1){pthread_mutex_lock(&m);a++;b++;if(a!=b){printf("%d!=%d\n",a,b);a=b=0;}pthread_mutex_unlock(&m);}}main(){pthread_t t1,t2;//2pthread_mutex_init(&m,0);//初始化互斥量 互斥量置1pthread_create(&t1,0,r1,0);pthread_create(&t2,0,r2,0);pthread_join(t1,(void**)0);//等待子进程结束pthread_join(t2,(void**)0);//4.pthread_mutex_destroy(&m);}
互斥锁/互斥量 mutex
1.定义互斥量pthread_mutex_t
2.初始化互斥量 1 pthread_mutex_init
3.互斥量操作 置0 phtread_mutex_lock
判定互斥量0:阻塞
1:置0,返回
置1 pthread_mutex_unlock
置1返回
强烈要求成对使用
4.释放互斥量pthread_mutex_destroy
结论:
互斥量保证锁定的代码一个线程执行,
但不能保证必需执行完!
5.在lock与unlock之间,调用pthread_exit,或者在线程外部调用pthread_cancel,
这两种行为都是遭鄙视的,其他线程被永久死锁.
pthread_cleanup_pop }
这对函数作用类似于atexit,取消线程时回调某个函数
注意:
这不是函数,而是宏.
必须成对使用
problem2.c
#include <stdio.h>#include <stdlib.h>#include <pthread.h>pthread_mutex_t m;void handle(void *d){// printf("退出后的调用!\n"); pthread_mutex_unlock(&m);}void* runodd(void *d){ int i=0; for(i=1;;i+=2) { pthread_cleanup_push(handle,0); //handle函数在线程调用return,pthread_exit,pthread_cancel, //或者下面函数参数为1时得到回调 pthread_mutex_lock(&m); printf("%d\n",i); pthread_cleanup_pop(1); }}void* runeven(void *d){ int i=0; for(i=0;;i+=2) { pthread_cleanup_push(handle,0); pthread_mutex_lock(&m); printf("%d\n",i); pthread_cleanup_pop(1); }}main(){ pthread_t todd,teven; pthread_mutex_init(&m,0); pthread_create(&todd,0,runodd,0); pthread_create(&teven,0,runeven,0); sleep(5); pthread_cancel(todd); pthread_join(todd,(void**)0); pthread_join(teven,(void**)0); pthread_mutex_destroy(&m);}6.多线程的应用
二.多线程同步
互斥量/信号/条件量/信号量/读写锁
1.sleep与信号
pthread_kill向指定线程发送信号
signal注册的是进程的信号处理函数.
pthread_kill+sigwait控制进程 如果线程sigwait来不及调用 不处理信号 则发给进程
1.1.定义信号集合
1.2.初始化信号集合
1.3.等待信号
1.4.其他线程发送信号
1.5.清空信号集合
thsignal.c
#include <stdio.h>#include <pthread.h>#include <unistd.h>#include <signal.h>pthread_t t1,t2;sigset_t sigs;void handle(int s){printf("信号!\n");}void*r1(void*d){int s;while(1){printf("线程--1\n");//sleep(1);sigwait(&sigs,&s);printf("接收到信号:%d!\n",s);}}void*r2(void*d){while(1){printf("线程----2\n");sleep(2);pthread_kill(t1,SIGUSR1);}}main(){sigemptyset(&sigs);sigaddset(&sigs,SIGUSR1);//sigfillset(&sigs);signal(SIGUSR1,handle);pthread_create(&t1,0,r1,0);pthread_create(&t2,0,r2,0);pthread_join(t1,(void**)0);pthread_join(t2,(void**)0);}
案例:
sigwait实际处理了信号
如果进程没有处理信号,目标线程也没有sigwait
,则进程会接收信号进行默认处理
信号量类似
2.1.定义条件量
2.2.初始化条件量
2.3.等待条件量
2.4.其他线程修改条件量
2.5.释放条件量
案例:
创建两个线程.
一个线程等待信号
一个线程每隔1秒发送信号
1.使用pause+pthread_kill
signal.c
#include <stdio.h>#include <pthread.h>#include <signal.h>pthread_t t1,t2;void handle(int s){}void *r1(void* d){while(1){pause();printf("活动!\n");}}void *r2(void* d){while(1){sleep(1);pthread_kill(t1,34);}}main(){signal(34,handle);pthread_create(&t1,0,r1,0);pthread_create(&t2,0,r2,0);pthread_join(t1,(void**)0);pthread_join(t2,(void**)0);}
signal2.c
#include <stdio.h>#include <pthread.h>#include <signal.h>pthread_t t1,t2;sigset_t sigs;void *r1(void* d){int s;while(1){sigwait(&sigs,&s);printf("活动!\n");}}void *r2(void* d){while(1){sleep(1);pthread_kill(t1,34);}}main(){sigemptyset(&sigs);sigaddset(&sigs,34);pthread_create(&t1,0,r1,0);pthread_create(&t2,0,r2,0);pthread_join(t1,(void**)0);pthread_join(t2,(void**)0);}
pthread_cond_*** 与sigwait都是进程同步控制
pthread_cond_***稳定
pthread_cond_***在环境下不会死锁.
signal3.c
#include <stdio.h>#include <pthread.h>#include <signal.h>pthread_t t1,t2;pthread_cond_t cond;//1.pthread_mutex_t m;void *r1(void* d){int s;while(1){pthread_cond_wait(&cond,&m);printf("活动!\n");}}void *r2(void* d){while(1){pthread_cond_signal(&cond);pthread_cond_signal(&cond);pthread_cond_signal(&cond);//只输出一次 条件量不会累计sleep(10);}}main(){pthread_mutex_init(&m,0);pthread_cond_init(&cond,0);//2pthread_create(&t1,0,r1,0);pthread_create(&t2,0,r2,0);pthread_join(t1,(void**)0);pthread_join(t2,(void**)0);pthread_cond_destroy(&cond);pthread_mutex_destroy(&m);}
练习:
使用条件量与互斥构造死锁程序.
deadlock.c
#include <stdio.h>#include <pthread.h>pthread_t t1,t2;pthread_mutex_t m1,m2;pthread_cond_t c;void* r1(void*d){ while(1) { pthread_mutex_lock(&m1); printf("我是等待!\n"); pthread_cond_wait(&c,&m1);//有解锁的功能 先解锁然后决定阻塞否 之后返回原状态 pthread_mutex_unlock(&m1); }}void* r2(void *d){ while(1) { pthread_mutex_lock(&m1); printf("我是让你不等待!\n"); pthread_cond_signal(&c); pthread_mutex_unlock(&m1); }}main(){ pthread_cond_init(&c,0); pthread_mutex_init(&m1,0); pthread_mutex_init(&m2,0); pthread_create(&t1,0,r1,0); pthread_create(&t2,0,r2,0); pthread_join(t1,0); pthread_join(t2,0); pthread_mutex_destroy(&m2); pthread_mutex_destroy(&m1); pthread_cond_destroy(&c);}
练习:
1.写一个程序:
两个线程写数据到文件.
数据格式:日期时间,线程ID\n
要求:
要求使用互斥, 保证数据正确.
体会使用互斥和不使用互斥的异同.
2.使用curses写一个多线程程序
开启26个线程.每个线程控制一个字母在屏幕上掉落
建议每隔字母的高度随机.
demo2.c
#include <pthread.h>#include <curses.h>#include <math.h>struct AChar{int x;int y;int speed;char a;};int stop=1;pthread_t t[26];pthread_t tid;pthread_mutex_t m;struct AChar a[26];void *run(void *d)//26个线程负责修改数据{int id;static idx=-1;idx++;id=idx;while(stop){pthread_mutex_lock(&m);//改变对象的y坐标a[id].y+=a[id].speed;if(a[id].y>=LINES){a[id].y=rand()%(LINES/4);}pthread_mutex_unlock(&m);sched_yield();usleep(100000);}}void * update(void *d)//另写一个线程 负责显示{int i=0;while(stop){erase();//绘制屏幕上for(i=0;i<26;i++){mvaddch(a[i].y,a[i].x,a[i].a);}//刷屏refresh();usleep(10000);}}main(){int i;initscr();curs_set(0);noecho();keypad(stdscr,TRUE);for(i=0;i<26;i++){a[i].x=rand()%COLS;a[i].y=rand()%(LINES/4);a[i].speed=1+rand()%3;a[i].a=65+rand()%26;}pthread_mutex_init(&m,0);pthread_create(&tid,0,update,0);for(i=0;i<26;i++){//随机产生字母与位置pthread_create(&t[i],0,run,0);}getch();stop=0;for(i=0;i<26;i++){//随机产生字母与位置pthread_join(t[i],(void**)0);}pthread_join(tid,(void**)0);pthread_mutex_destroy(&m);endwin();}
3.写一个程序:创建两个线程
一个线程负责找素数.
另外一个线程把素数保存到文件
要求:
找到以后,通知另外一个线程保存,停止招素数
线程保存好以后通知素数查找线程继续查找.
目的:
互斥与信号/条件量作用是不同.
0 0
- Linux——线程同步
- linux线程同步——条件变量
- Linux——线程同步和线程安全
- linux 线程 线程同步
- 同步线程—Mutex
- 线程同步—互斥锁
- Linux的新式线程同步原语——Futex
- Linux的新式线程同步原语——Futex
- Linux下线程同步对象(1)——互斥量
- Linux下线程同步对象(2)——读写锁
- Linux下线程同步对象(3)——条件变量
- Linux下线程同步对象(1)——互斥量
- Linux下线程同步对象(2)——读写锁
- Linux下线程同步对象(3)——条件变量
- Linux多线程——使用信号量同步线程
- Linux多线程——使用互斥量同步线程
- Linux多线程——使用互斥量同步线程
- Linux多线程——使用互斥量同步线程
- A JSONObject text must begin with '{' at character 1 of 1
- Linux 下给项目搭建svn环境
- 数学之路-数据分析进阶-多变量数据分析(3)
- C#内存回收
- Entity Framework 并发处理
- Linux——线程同步
- 树莓派学习笔记(1):入手树莓派
- DRAM SRAM SDRAM区别
- python中subprocess与pipe管道
- [互联网面试笔试汇总C/C++-6] 迅雷
- 改变世界的17个等式
- codeforces-#471A. MUH and Sticks(模拟)
- 滤波器设计指标
- 数字信号处理中各种频率关系