线程概念

线程:Linux下,线程又被称为轻量级进程,是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。线程是进程中的一个实体,是被系统独立调度和分派的基本单元。线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。

线程状态:


进程和线程的关系

(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程是操作系统可识别的最小执行和调度单位。

(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。 同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量。

(3)处理机分给线程,即真正在处理机上运行的是线程。

(4)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。


创建线程

POSIX线程库,链接这些线程函数时要使用“-lpthread”选项。

 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

代码如下;

5 void *thr_start(void *arg)6 {7         while(1)8         {9                 printf("I'm calling\n");10                 sleep(1);11         }12         return NULL;13 }14 int main()15 {16         pthread_t tid;17         //pthread_create创建线程,线程入口函数为thr_start18         int ret=pthread_create(&tid,NULL,thr_start,NULL);19         if(ret!=0)20                 perror("pthread_create"),exit(1);21         while(1)22         {23                 printf("i'm playing game\n");24                 sleep(1);25         }26         return 0;27 }

用ps - eLf查看:

多线程的进程,又被称为线程组,线程组内的每一个线程在内核之中都存在一个进程描述符(task_struct)与之对应。进程描述符结构体中的pid,对应的是线程ID(LWP);进程描述符中tgid(主线程pid),对应用户层面的进程ID.。


线程终止

void pthread_exit(void *retval);

注意:pthread_exit 或 return 返回的指针所指向的内存单元必须是全局的或者用malloc分配的,不能在线程函数的栈上分配,因为当其他线程得到这个返回指针时线程函数已经退出了。

线程取消
int pthread_cancel(pthread_t thread);


线程等待和分离

线程等待:int pthread_join(pthread_t thread, void **retval);
线程分离:int pthread_detach(pthread_t thread);

线程的返回值

  • 线程通过return返回, retval所指向的单元里存放的是thread线程函数的返回值;
  • 通过调用pthread_cancel异常终止,retval所指向的单元里存放的是常数-1(PTHREAD_CANCELED).
  • 调用pthread_exit终止,retval所指向的单元里存放的是传给pthread_exit的参数。
    代码如下:
  6 void *thread1(void *arg)7 {8         printf("thread 1 return  \n");9         int *p=(int *)malloc(sizeof(int));10         *p=1;11         return (void *)p;12 }13 void *thread2(void *arg)14 {15         printf("thread 2  exit  \n");16         int *p=(int *)malloc(sizeof(int));17 18         *p=2;19         pthread_exit((void *)p);20 }21 void *thread3(void *arg)22 {23         while(1)24         {25                 printf("thread 3 run  \n");26                 sleep(1);27         }28         return NULL;29 }30 int main()31 {32         pthread_t tid;33         void *ret;34 35         //thread 1 return36         pthread_create(&tid,NULL,thread1,NULL);37         pthread_join(tid,&ret);38         printf("thread return ,thread id %x,return code:%d\n",tid,*(int *)ret);39         free(ret);40 41         //thread 2 exit42         pthread_create(&tid,NULL,thread2,NULL);43         pthread_join(tid,&ret);44         printf("thread return ,thread id %x,return code:%d\n",tid,*(int *)ret);45         free(ret);46 47         //thread 3 cancel by other48         pthread_create(&tid,NULL,thread3,NULL);49         sleep(3);50         pthread_cancel(tid);51         pthread_join(tid,&ret);52         if(ret==-1)53         {54                 printf("thread return ,thread id %x,return code:PTHREAD_CANCELED\n",tid);55         }56         else57         {58 59                 printf("thread return ,thread id %x,return code:NULL\n",tid);60         }61 62         return 0;63 }

线程分离
默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join,否则无法释放资源,从而造成系统泄露。

当一个线程 被分离后,这个线程无法被pthread_join等待,否则返回EINVAL错误,如图:
线程被分离后,这个线程退出后,自动释放资源,不需要被等待。

5 void *thread_run(void *arg)6 {7         pthread_detach(pthread_self());//pthread_self()获取线程自己的ID8         printf("%s\n",(char *)arg);9         return NULL;10 }11 int main()12 {13         pthread_t tid;14         if(pthread_create(&tid,NULL,thread_run,"thread1 run ...")!=0)15         {16                 perror("pthread_create"),exit(1);17         }18         int ret=0;19         sleep(1);20 21         if(pthread_join(tid,NULL)==0)22         {23                 printf("pthread wait success\n");24         }25         else26         {27                 printf("pthread wait failed\n");28                 ret=1;29         }30         return 0;31 32 }


线程同步与互斥

mutex互斥量:有时需要线程间共享时,需要对临界资源进行互斥

pthread_mutex_init()初始化互斥锁
pthread_mutex_destroy()删除互斥锁
pthread_mutex_lock():占有互斥锁(阻塞操作)
pthread_mutex_trylock():试图占有互斥锁(不阻塞操作)。即,当互斥锁空闲时,将占有该锁;否则,立即返回。
pthread_mutex_unlock(): 释放互斥锁

条件变量:当一个线程访问资源时,资源已空,它只能等待,直到有其他线程释放了一个资源
pthread_cond_init():初始化条件变量
pthread_cond_destroy():销毁条件变量
pthread_cond_signal(): 发送一个信号给正在当前条件变量的线程队列中处于阻塞等待状态的线程,使其脱离阻塞状态,唤醒后继续执行。如果没有线程处在阻塞等待状态,pthread_cond_signal也会成功返回。一般只给一个阻塞状态的线程发信号。假如有多个线程正在阻塞等待当前条件变量,则根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。
pthread_cond_wait(): 等待条件变量的特殊条件发生;pthread_cond_wait() 必须与一个pthread_mutex配套使用。该函数调用实际上依次做了3件事:

  • 对当前pthread_mutex解锁
  • 把当前线程挂起到当前条件变量的线程队列
  • 被其它线程的信号唤醒后对当前pthread_mutex申请加锁
    如果线程收到一个信号被唤醒,将被配套的互斥锁重新锁住,

pthread_cond_broadcast唤醒全部线程

用互斥量和条件变量实现消费者——生产者模型(只有一个消费者和生产者)

  6 int goods=0;7 pthread_mutex_t mutex;8 pthread_cond_t cond;9 void *thr_productor(void *arg)10 {11         while(1)12         {13                 if(goods==0)14                 {15                         printf("product a food\n");//物品为0时,生产16                         goods=1;17                         sleep(1);18                         pthread_cond_signal(&cond);//通知19                 }20         }21         return NULL;22 }23 24 void *thr_consumer(void *arg)25 {26         while(1)27         {28                 if(goods==0)//没有物品,就等待29                 {30                         pthread_cond_wait(&cond,&mutex);31                 }32                 printf("I got it\n");//代表有物品了33                 goods=0;//得到之后就将它置为034         }35         return NULL;36 37 }38 int main()39 {40         pthread_t tid1,tid2;41         int ret;42         pthread_cond_init(&cond,NULL);43         pthread_mutex_init(&mutex,NULL);44         ret=pthread_create(&tid1,NULL,thr_productor,NULL);45         if(ret!=0)46                 perror("pthread_create"),exit(1);47 48         ret=pthread_create(&tid1,NULL,thr_consumer,NULL);49         if(ret!=0)50                 perror("pthread_create"),exit(1);51         pthread_join(tid1,NULL);52         pthread_join(tid2,NULL);53         pthread_cond_destroy(&cond);54         pthread_mutex_destroy(&mutex);55         return 0;56 }

POSIX信号量—-同步操作,达到无冲突的访问共享资源

sem_wait:申请共享资源,所指定信号灯的值如果大于0,那就将它减1并立即返回,就可以使用申请来的共享资源了。如果该值等于0,调用线程就被进入睡眠状态,直到该值变为大于0,这时再将它减1,函数随后返回。sem_wait操作必须是原子操作。
sem_post:释放共享资源。与sem_wait恰相反。
sem_init:初始化非命名(内存)信号量
sem_destroy:摧毁非命名信号量

用POSIX信号量实现生产者–消费者(一对一):

  6 sem_t sem_producer;7 sem_t sem_consumer;8 void *thr_producer(void *arg)9 {10         while(1)11         {12                 sem_wait(&sem_producer);13                 sleep(1);14                 printf("P:product a food\n");15                 sem_post(&sem_consumer);16         }17 }18 void *thr_consumer(void *arg)19 {20         while(1)21         {22                 sem_wait(&sem_consumer);23                 printf("C:eat a food\n");24                 sem_post(&sem_producer);25 26         }27 }28 int main()29 {30         pthread_t tid1,tid2;31         int ret;32 33         sem_init(&sem_producer,0,0);34         sem_init(&sem_consumer,0,1);//初始化消费者线程初始值为1,表示消费者先吃35         ret=pthread_create(&tid1,NULL,thr_producer,NULL);36         if(ret!=0)37                 perror("pthread_create"),exit(1);38 39         ret=pthread_create(&tid2,NULL,thr_consumer,NULL);40         if(ret!=0)41                 perror("pthread_create"),exit(1);42         pthread_join(tid1,NULL);43         pthread_join(tid2,NULL);44 45         sem_destroy(&sem_producer);46         sem_destroy(&sem_consumer);47 }

读写锁:处理多读少写情况
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t
*restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
nt pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
自旋锁–适合短时间内完成的工作

  4 //读写锁的实现5 char *str="I am a point";6 pthread_rwlock_t rwlock;7 void *thr_write(void *arg)8 {9         pthread_t p=pthread_self();10         while(1)11         {12                 pthread_rwlock_wrlock(&rwlock);13                 printf("W:%p*** writing*** %s\n",p,str);14                 sleep(1);15                 printf("W:****%p***amazing\n",p);16                 pthread_rwlock_unlock(&rwlock);17                 usleep(100);18         }19         return NULL;20 }21 void *thr_read(void *arg)22 {23         pthread_t p=pthread_self();24         while(1)25         {26                 pthread_rwlock_rdlock(&rwlock);27                 printf("R:%p*** reading*** %s\n",p,str);28                 sleep(1);29                 printf("R:****%p***amazing\n",p);30                 pthread_rwlock_unlock(&rwlock);31                 usleep(100);32         }33         return NULL;34 }35 36 int main()37 {38         pthread_t tid1[2],tid2[2];39 40         pthread_rwlock_init(&rwlock,NULL);41 42         pthread_create(&tid1[0],NULL,thr_write,NULL);43         pthread_create(&tid1[1],NULL,thr_write,NULL);44 45         pthread_create(&tid1[0],NULL,thr_read,NULL);46         pthread_create(&tid1[1],NULL,thr_read,NULL);47 48         pthread_join(tid1[0],NULL);49         pthread_join(tid1[1],NULL);50         pthread_join(tid2[0],NULL);51         pthread_join(tid2[1],NULL);52 53         pthread_rwlock_destroy(&rwlock);54 }

可以看出读 可以同时多个线程读,但写 只能一个线程写完后另一个线程写 ,并且在写的过程中不允许读。

【Linux】浅谈线程相关推荐

  1. 浅谈线程池(下):相关试验及注意事项

    三个月,整整三个月了,我忽然发现我还有三个月前的一个小系列的文章没有结束,我还欠一个试验!线程池是.NET中的重要组件,几乎所有的异步功能依赖于线程池.之前我们讨论了线程池的作用.独立线程池的存在意义 ...

  2. 浅谈线程池(中):独立线程池的作用及IO线程池

    在上一篇文章中,我们简单讨论了线程池的作用,以及CLR线程池的一些特性.不过关于线程池的基本概念还没有结束,这次我们再来补充一些必要的信息,有助于我们在程序中选择合适的使用方式. 独立线程池 上次我们 ...

  3. 浅谈线程池(上):线程池的作用及CLR线程池

    线程池是一个重要的概念.不过我发现,关于这个话题的讨论似乎还缺少了点什么.作为资料的补充,以及今后文章所需要的引用,我在这里再完整而又简单地谈一下有关线程池,还有.NET中各种线程池的基础.更详细的内 ...

  4. Linux 浅谈代码打印到终端的缓冲区(进度条程序)

    我们知道printf是向终端显示打印数据,是我们想要看到程序的结果,而在linux系统下一切皆文件,在终端显示是要有显示器设备的,在linux下把显示器设备当做文件进行操作,将数据写入到显示器设备文件 ...

  5. java浅谈线程安全之锁

    在java锁的知识中,我们首先要知道分布式锁和本地锁的概念. 1.本地锁: 在单进程的系统中,存在多个线程去同时操作某个共享变量时,就需要使用本地锁,最常用的关键字:synchronized 2.分布 ...

  6. linux 目录的粘滞位,Linux浅谈SUID,SGID,Sticky粘滞位对目录以及文件的相关作用

    我们知道在Linux中,root管理员的权限是很大的,能够支持执行绝大部分程序以及命令进而对文件进行相对应的修改,写入.当然这些作用只能体现在root管理员上.但是有一个现象,有些普通用户是可以通过p ...

  7. Linux | 浅谈Shell运行原理【王婆竟是资本家】

    文章目录

  8. 浅谈linux线程模型和线程切换

    本文从linux中的进程.线程实现原理开始,扩展到linux线程模型,最后简单解释线程切换的成本. 刚开始学习,不一定对,好心人们快来指正我啊啊啊!!! linux中的进程与线程 首先明确进程与进程的 ...

  9. linux 线程_浅谈Linux线程模型

    Thread Basic 基础概念 线程是操作系统能够调度和执行的基本单位,在Linux中也被称之为轻量级进程.从定义中可以看出,线程它是操作系统的概念,在不同的操作系统中的实现是不同的,不过今天分享 ...

最新文章

  1. Python3 统计 ftp 文件个数和大小
  2. Java内存分配原理
  3. java synchronized wait
  4. SAP Spartacus注入自定义的CurrentProductService
  5. linux的ctrl alt f6的作用,Linux(Centous6.4)操作系统中,快捷键Alt+Ctrl+F10是什么作用?...
  6. ASP.NET使用数据库存储、读取并修改图片
  7. python 反爬机制_python3爬虫--反爬虫应对机制
  8. mysql的max case_MySQL -- 行转列 -- GROUP_CONCAT -- MAX(CASE WHEN THEN)
  9. Win10应用商店无法连接解决方案
  10. Redis:30分钟从入门到精通 - 2P
  11. x264代码剖析(四):vs2010编译x264错误集锦
  12. 【智能家居篇】wifi网络结构(下)
  13. Java定时器cron表达式
  14. 记账系统推荐金蝶精斗云_小编总结了金蝶精斗云财务软件的优劣势
  15. 递归(recurse)与迭代(iteration)
  16. spss需要计算机代码,SPSS编程操作入门
  17. RecyclerView 报Scrapped or attached views may not be recycled. as Scrap:false isAttached:true异常
  18. php股票t 0,股票T+0是什么意思?如何看懂股票T+0?
  19. 2022北京高考数学压轴题21题的一种解答
  20. [转] 理解各种熵最大熵模型

热门文章

  1. 模拟电路中的“基础积木”是什么?
  2. java楼盘管理系统_基于Java的楼盘销售管理系统的设计与实现
  3. word文档计算机排版,Word文件在不同电脑排版不同怎么办
  4. 金山-垃圾清理模块架构
  5. 光伏并网逆变器资料,包含原理图
  6. OpenWrt CF卡制作过程
  7. Linux内核活动之中断1
  8. 中国最牛地级市——潍坊
  9. 马云的双11计算机发展史图片,阿里张建锋:今年双11是机器和人一起来指挥
  10. 如何把自己的笔记本做成一个wifi热点共享网络