Linux多线程编程——多线程与线程同步
多线程
使用多线程好处:
一、通过为每种事件类型的处理单独分配线程,可以简化处理异步事件的代码,线程处理事件可以采用同步编程模式,启闭异步编程模式简单
二、方便的通信和数据交换
由于进程之间具有独立的数据空间,多进程必须使用操作系统提供的复杂机制才能实现内存和文件描述符的共享,导致上下文切换的开销比较大。而线程之间共享进程的所有资源,所以,多线程可以访问相同的存储空间和文件描述符。
三、对一些不具有互斥型的问题,可以将其分解为从而改善程序的吞吐量。对于进程,在完成多个任务时,实际上需要将任务串行化。对于多线程,相互独立而且想不不依赖的任务可以交叉运行,只需要为每个任务分配一个线程即可。
四、交互的程序可以通过使用多线程实现响应时间的改善,多线程可以把程序中用于处理用户输入输出的部分与其他部分分开。
线程包含了进程内执行环境必须的信息,包括进程ID,一组寄存器值,栈,调度优先级和策略,信号屏蔽字,errno变量以及线程私有数据。
线程ID使用pthread_t数据类型来表示,类似于一种结构体,可以使用 pthread_self 函数和 pthread_equal 函数来通过线程ID识别线程。
原型:
#include <pthread.h>
int pthread_eaual(pthread_t tid1,pthread_t tid2); //判断两个线程ID是否相等
相等返回非0,不相等返回0
#include <pthread.h>
pthread_t pthread_self(void); //获取自身线程ID
返回调用线程的ID
线程创建
#include <pthread.h>
int pthread_creat(pthread_t *restrict tidp,const pthread_attr_t *attr,void*(*start_rtn)(void),void *restrict arg); //创建线程
成功返回0,否则返回错误编号
tidp 指向的内存单元被设置为新创建的现成的线程ID
attr 用于定制线程的线程属性,设置为NULL时,则使用默认属性
新创建的函数从strat_rtn函数的地址开始运行,该函数只有一个无类型指针参数arg.若要想向strat_rtn传递不知一个参数,可以将多个参数放在一个结构体中,然后把结构体的地址作为arg参数传入。
线程终止
如果进程中的任一线程调用了exit,_Exit或_exit,则整个进程会终止。同样,如果信号的默认动作是终止进程,那么,把信号发送到进程会终止整个进程。
单个进程的退出方式有三种:
1、线程只是从启动的例程中退出,返回值是线程的终止码;
2,、线程可以被统一进程中的其他线程取消;
3、线程调用pthread_exit;
#include<pthread.h>
void pthread_exit(void *rval_ptr);
线程通过调用pthread_exit函数终止执行,就如同进程在结束时调用exit函数一样。这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针。
rval_ptr是一个无类型的指针,与传递给启动例程的单个参数类似,可以通过进程中的其他线程调用pthread_join函数访问这个指针。
#include<pthread.h>
int pthread_join(pthread_t thread,void **rval_ptr);
成功返回0;否则返回错误编号
pthread_join()函数,以阻塞的方式等待thread指定的线程调用pthread_exit、冲启动例程中返回或者被取消。当函数返回时,被等待线程的资源被收回。
如果线程已经结束,那么该函数会立即返回。并且thread指定的线程必须是joinable的。
thread: 线程标识符,即线程ID,标识唯一线程。rval_ptr: 用户定义的指针,用来存储被等待线程的返回值。
如果线程是从启动例程中返回,
rval_ptr将包含返回码,如果线程被取消,由rval_ptr指向的内存单元被置为PTHREAD_CANCELED。
线程同步
线程同步机制包括互斥,读写锁以及条件变量
互斥
可以把互斥变量之置为常量PTHREAD_MUTEX_INITIALIZER(针对静态分配的互斥量),或调用pthread_mutex_init函数进行初始化。如果动态的分配互斥量(如调用malloc函数),那么在释放内存前需要调用pthread_mutex_destory。
#include<pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destory(pthread_mutex_t mutex);
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_trylock尝试对互斥量进行加锁。如果调用pthread_mutex_trylock时互斥量处于未锁住状态,则pthread_mutex_trylock将互斥量锁住,不会出现阻塞并返回0,否则失败并返回EBUSY。
读写锁
初始化
#include<pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); //初始化
int pthread_rwlock_destory(pthread_rwlock_t *restrict rwlock); //销毁读写锁,
成功返回0,错误返回错误编号;
锁定读写锁与解锁
#include<pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t rwlock); //在读模式下锁定读写锁
int pthread_rwlock_wrlock(pthread_rwlock_t rwlock); //在写模式下锁定读写锁
int pthread_rwlock_unlock(pthread_rwlock_t rwlock); //解锁
成功返回0,错误返回错误编号;
条件变量
和互斥量一样,可以把条件变量之置为常量PTHREAD_COND_INITIALIZER(针对静态分配的条件变量),或调用pthread_cond_init函数进行初始化。在释放内存前需要调用pthread_cond_destory函数对变量进行去除初始化。
#include<pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destory(pthread_cond_t cond);
成功返回0,否则返回错误编号
条件变量是与条件测试一起使用的,通常线程会对一个条件进行测试,如果条件不满足调用条件等待函数就等待条件满足。
#include<pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, const pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond, const pthread_mutex_t *restrict mutex,const struct timespec *rectrict timedout);
成功返回0,否则返回错误编号
cond是一个指向条件变量的指针,mutex是一个指向互斥量的指针,线程在调用前应该拥有这个互斥量。传递给pthread_cond_wait的互斥量对条件进行保护,调用者吧锁住的互斥量传递给函数,函数把调用线程防盗等待条件的线程列表上,然后互斥量解锁,pthread_cond_wait返回时,互斥量再次被锁住。
pthread_cond_timedwait与pthread_cond_wait工作方式相似,只是多了一个timeout。timeout是一个绝对值而不是相对值。其为需要等待的时间加上当前时间,即未来某一时刻。
timeout通过timespec结构指定:
struct timespec{
time_t tv_sec;
time_t tv_nsec;
};
可以使用gettimeofday获取用timeval表示的当前时间,然后把等待时间转化成timespec结构。
可以使用一下函数得到timeout值得绝对时间
void maketimeout(struct timespec *tsp,long minutes)
{
struct timeval now;
gettimeofday(&now); //获取当前时间
tsp->tv_sec=now.tv_sec;
tsp->tv_nsec=now.tv_usec*1000; //usec转换成nsec
tsp->tv_sec+=minutes*60;
}
pthread_cond_signal和pthread_cond_broadcast两个函数用来通知线程条件已经满足。
pthread_cond_signal在条件满足后唤醒等待条件的某一个线程,而pthread_cond_broadcast将唤醒所有线程。
#include<pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
成功返回0,否则返回错误编号
注意:一定要在条件状态改变以后再给线程发信号
Linux多线程编程——多线程与线程同步的更多相关文章
- 《Linux多线程服务端编程》笔记——线程同步精要
并发编程基本模型 message passing和shared memory. 线程同步的四项原则 尽量最低限度地共享对象,减少需要同步的场合.如果确实需要,优先考虑共享 immutable 对象. ...
- Linux系统编程@多线程编程(一)
多线程编程 涉及操作系统原理概念 时间片 进程状态 上下文: 对进程来说,就是进程的执行环境,具体就是各个变量和数据,包括所有的寄存器变量.打开的文件.内存信息等. 进程的写时复制:由于一般 fork ...
- Linux系统编程@多线程编程(二)
线程的操作 线程标识 线程的ID表示数据类型:pthread_t (内核中的实现是unsigned long/unsigned int/指向pthread结构的指针(不可移植)几种类型) 1.对两个线 ...
- 多线程编程-- part 2 线程的生命周期和优先级
线程的创建到消亡的历程: java多线程的5种状态: (1)New(新建) new Thread(run()) 该线程还没开始运行,状态是new,在程序运行前还有一些基础工作要做 (2)runnabl ...
- iOS多线程编程之创建线程安全(转载)
一.多线程的安全隐患 资源共享 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象.同一个变量.同一个文件 当多个线程访问同一块资源时,很容易引发数据错乱和数 ...
- java多线程(2) 线程同步
我们对线程访问同一份资源的多个线程之间,来进行协调的这个东西,就是线程同步. 例子1:模拟了多个线程操作同一份资源,可能带来的问题: package com.cy.thread; public c ...
- Python多线程(2)——线程同步机制
本文介绍Python中的线程同步对象,主要涉及 thread 和 threading 模块. threading 模块提供的线程同步原语包括:Lock.RLock.Condition.Event.Se ...
- java多线程编程(二创建线程)
1.概念 因为java是完全面向对象的,所以在java中,我们说的线程,就是Thread类的一个实例对象.所以,一个线程就是一个对象,它有自己字段和方法. 2.创建线程 创建线程有 ...
- C#多线程:深入了解线程同步lock,Monitor,Mutex,同步事件和等待句柄(中)
本篇继续介绍WaitHandler类及其子类 Mutex,ManualResetEvent,AutoResetEvent的用法..NET中线程同步的方式多的让人看了眼花缭乱,究竟该怎么去理解呢?其实, ...
随机推荐
- iOS开发小技巧--高斯模糊框架的应用
事件背景:彩票项目中点击检查更新之后的操作,高斯模糊效果并弹出HUD 注意:在应用别人的框架的时候,最好封装一下下. 新建一个类 继承自高斯模糊的类. 使用方法:新建一个高斯模糊类的View,添加到 ...
- zabbix_agent安装(Centos+Ubuntu)
Centos安装 安装依赖包 yum -y install mysql-devel libcurl-devel net-snmp-devel 添加用户 groupadd zabbix use ...
- hdu2846 字典树
给你一堆字符串,然后再给你几个查询,前面那些字符串中有多少个包含了这个串.所以可以把开始inset()的字符遍历一遍,同时可能出现该字符串在某个字符串中有多次出现,所以还要用flag标记,来区分不同的 ...
- 【poj1740】 A New Stone Game
http://poj.org/problem?id=1740 (题目链接) 男人八题之一 题意 对于n堆石子,每堆若干个,两人轮流操作,每次操作分两步,第一步从某堆中去掉至少一个,第二步(可省略)把该 ...
- Linux /proc、/dev Principle
目录 . /proc简介 . 内核机制相关 . 进程信息 . 硬件设备相关 . 系统信息 . /dev简介 . 内存相关 1. /proc简介 在linux的根目录下有一个/proc目录,/proc文 ...
- 使用JMeter创建数据库(Mysql)测试
我的环境:MySQL:mysql-essential-5.1.51-win32 jdbc驱动:我已经上传到csdn上一个:http://download.csdn.net/source/3451945 ...
- AndroidManifest File Features
http://www.android-doc.com/guide/topics/manifest/manifest-intro.html The following sections describe ...
- 软件开发过程中的审查 (Review)
http://blog.csdn.net/horkychen/article/details/5035769 软件开发过程中的审查 (Review) 希望别人做些什么->定义出流程 希望别人 ...
- Enum类型 枚举内部值/名
enum Days { Nothing=0, Mon=1, Stu=2 } static void Main(string[] args) { foreach (int item in Enum.Ge ...
- PHP实现发红包程序(helloweba网站经典小案例)
我们先来分析下规律. 设定总金额为10元,有N个人随机领取: N=1 第一个 则红包金额=X元: N=2 第二个 为保证第二个红包可以正常发出,第一个红包金额=0.01至9.99之间的某个随机数. 第 ...