linux编程之多线程编程
我们知道,进程在各自独立的地址空间中运行,进程之间共享数据需要用mmap或者进程间通信机制,有些情况需要在一个进程中同时执行多个控制流程,这时候线程就派上了用场,比如实现一个图形界面的下载软件,一方面需要和用户交互,等待和处理用户的鼠标键盘事件,另一方面又需要同时下载多个文件,等待和处理从多个网络主机发来的数据,这些任务都需要一个“等待-处理”的循环,可以用多线程实现,一个线程专门负责与用户交互,另外几个线程每个线程负责和一个网络主机通信。信号处理函数是同一个进程地址空间中的多个控制流程,多线程也是如此,但是比信号处理函数更加灵活,信号处理函数的控制流程只是在信号递达时产生,在处理完信号之后就结束,而多线程的控制流程可以长期并存,操作系统会在各线程之间调度和切换,就像在多个进程之间调度和切换一样。由于同一进程的多个线程共享同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:
- 文件描述符表
- 每种信号的处理方式(SIG_IGN、SIG_DFL或者自定义的信号处理函数)
- 当前工作目录
- 用户id和组id
但有些资源是每个线程各有一份的:
- 线程id
- 上下文,包括各种寄存器的值、程序计数器和栈指针
- 栈空间
- errno变量
- 信号屏蔽字
- 调度优先级
1.创建线程
include <pthread.h> int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
返回值:成功返回0,失败返回错误号。以前学过的系统函数都是成功返回0,失败返回-1,而错误号保存在全局变量errno中,而pthread库的函数都是通过返回值返回错误号,虽然每个线程也都有一个errno,但这是为了兼容其它函数接口而提供的,pthread库本身并不使用它,通过返回值返回错误码更加清晰。在一个线程中pthread_create()创建新的线程后,当前线程从pthread_create()返回继续往下执行,而新的线程所执行的代码由我们传给
pthread_create的函数指针start_routine决定。
2.终止线程
如果需要只终止某个线程而不终止整个进程,可以有三种方法:
- 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。
- 一个线程可以调用pthread_cancel终止同一进程中的另一个线程。
- 线程可以调用pthread_exit终止自己。
pthread_cancel
#include <pthread.h> void pthread_exit(void *retval);
#include <pthread.h>
int pthread_join(pthread_t th, void **thread_return);
如果成功,返回值存储在thread_return中,并返回0,否则返回错误码:
ESRCH:找不到指定线程
EINVAL:线程th是detached或者已经存在另一个线程在等待线程th结束
EDEADLK:th的参数引用它自己(即线程不能join自身)
一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL。对一个尚未detach的线程调pthread_join或pthread_detach都可以把该线程置为detach状态,也就是说,不能对同一线程调用两次pthread_join,或者如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。
#include <pthread.h> int pthread_detach(pthread_t tid);
返回值:成功返回0,失败返回错误号
以下为一个例子:

程序执行结果:

3.线程间同步
对于多线程的程序,访问冲突的问题是很普遍的,解决的办法是引入互斥锁(Mutex,Mutual Exclusive Lock),获得锁的线程可以完成“读-修改-写”的操作,然后释放锁给其它线程,没有获得锁的线程只能等待而不能访问共享数据,这样“读-修改-写”三步操作组成一个原子操作,要么都执行,要么都不执行,不会执行到中间被打断,也不会在其它处理器上并行做这个操作。
Mutex用pthread_mutex_t类型的变量表示,可以这样初始化和销毁:
#include <pthread.h> int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
返回值:成功返回0,失败返回错误号。
pthread_mutex_init函数对Mutex做初始化,参数attr设定Mutex的属性,如果attr为NULL则表示缺省属性,Mutex属性以后再讲。用pthread_mutex_init函数初始化的Mutex可以用pthread_mutex_destroy销毁。如果Mutex变量是静态分配的(全局变量或static变量),也可以用宏定PTHREAD_MUTEX_INITIALIZER来初始化,相当于用pthread_mutex_init初始化并且attr参数为NULL。Mutex的加锁和解锁操作可以用下
列函数:
#include <pthread.h> int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回0,失败返回错误号。
一个线程可以调用pthread_mutex_lock获得Mutex,如果这时另一个线程已经调用pthread_mutex_lock获得了该 Mutex,则当前线程需要挂起等待,直到另一个线程调用pthread_mutex_unlock释放Mutex,当前线程被唤醒,才能获得该 Mutex并继续执行。如果一个线程既想获得锁,又不想挂起等待,可以调用pthread_mutex_trylock,如果Mutex已经被另一个线程获得,这个函数会失败返回EBUSY,而不会使线程挂起等待。
以下为程序例子:


4.信号量控制线程的互斥与同步
信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作。而互斥锁是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这 个资源。只要信号量的value大于0,其他线程就可以sem_wait成功,成功后信号量的value减一。若value值不大于0,则sem_wait使得线程阻塞,直到sem_post释放后value值加一,但是sem_wait返回之前还是会将此value值减一.


linux编程之多线程编程的更多相关文章
- 【转】 Linux下的多线程编程
作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/原文链接:http://www.cnblogs.com/gnuhpc/archive/2012/12/07/280 ...
- Linux下的多线程编程
1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的 Unix也支持线程的概念,但是在一个进程(proces ...
- 【转】Linux下的多线程编程
1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的 Unix也支持线程的概念,但是在一个进程(proces ...
- 《转》Linux下的多线程编程
原地址:http://linux.chinaunix.net/doc/program/2001-08-11/642.shtml 1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程 ...
- 每天进步一点点——论fork()函数与Linux中的多线程编程
转载请说明出处:http://blog.csdn.net/cywosp/article/details/27316803 一.fork()函数 在操作系统的基本概念中进程是程序的一次运行,且是 ...
- 【转】Linux下的多线程编程背景知识
1. 进程和线程 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的 Unix也支持线程的概念,但是在一个进程(pr ...
- Linux C++的多线程编程(转)
1. 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的Unix也支持线程的概念,但是在一个进程(proces ...
- Linux C语言多线程编程实例解析
Linux系统下的多线程遵循POSIX线程接口,称为 pthread.编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a.顺便说一下,Linux ...
- SDK编程之多线程编程
本课中,我们将学习如何进行多线程编程.另外我们还将学习如何在不同的线程间进行通信. 理论:前一课中,我们学习了进程,其中讲到每一个进程至少要有一个主线程.这个线程其实是进程执行的一条线索,除此主线程外 ...
- Java多线程编程(2)--多线程编程中的挑战
一.串行.并发和并行 为了更清楚地解释这三个概念,我们来举一个例子.假设我们有A.B.C三项工作要做,那么我们有以下三种方式来完成这些工作: 第一种方式,先开始做工作A,完成之后再开始做工作B ...
随机推荐
- [socket编程] 一个服务器与多个客户端之间通信
转自:http://blog.csdn.net/neicole/article/details/7539444 并加以改进 Server程序: // OneServerMain.cpp #includ ...
- Bootstrap排版类
类 描述 实例 .lead 使段落突出显示 尝试一下 .small 设定小文本 (设置为父文本的 85% 大小) 尝试一下 .text-left 设定文本左对齐 尝试一下 .text-center 设 ...
- RT-thread内核之内核对象模型
RT-Thread的内核对象模型是一种非常有趣的面向对象实现方式.由于C语言更为面向系统底层,操作系统核心通常都是采用C语言和汇编语言混合编写而成.C语言作为一门高级计算机编程语言,一般被认为是一种面 ...
- C# 跨服务大文件复制
跨服务的大文件复制,肯定要和本地大文件复制一样,分多次传递,要不然内存也承受不了,下面就说下如何实现大文件的跨服务复制······ 首先肯定要建立一个WCF的服务以及对应的客户端来测试服务,此方法请参 ...
- Vue语法笔记
Vue.js 的核心是一个允许采用简洁的模板语法来声明式的将数据渲染进 DOM: 事件监听:v-on 指令绑定一个事件监听器 缩写[@] v-on:click 用户输入,绑定数据:v-model ...
- 51nod 1257 背包问题 V3(分数规划)
显然是分数规划...主要是不会求分数的形式,看了题解发现自己好傻逼QAQ 还是二分L值算出d[]降序选K个,顺便记录选择时候的p之和与w之和就可以输出分数形式了... #include<iost ...
- [学习笔记]NTT——快速数论变换
先要学会FFT[学习笔记]FFT——快速傅里叶变换 一.简介 FFT会爆精度.而且浮点数相乘常数比取模还大. 然后NTT横空出世了 虽然单位根是个好东西.但是,我们还有更好的东西 我们先选择一个模数, ...
- angularJS批量删除 品优购删除品牌(通用复选框批量选中删除解决思路)
思路: 一步:在点击复选框时维护变量数组 在js中定义一个数组变量, 给复选框添加点击动作, 在动作中判断当前复选框是否为选中状态(即点击后复选框的是否选中状态), 若为选中状态,则向数组中添加选中的 ...
- Android JUnit test
Android单元测试步骤 1.修改AndroidManifest.xml文件. 添加instrumentation节点.其中name是固定值,targetPackage为需要测试的类所在的包.如: ...
- [mysql]数据库引擎查看
1.查看数据库引擎 全局下,show engines; 2.察看数据库引擎 show variables like '%engine%'; 或者show create table xxx\G 会显示默 ...