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中线程同步的方式多的让人看了眼花缭乱,究竟该怎么去理解呢?其实, ...
随机推荐
- WebForm之Linq组合查询
组合查询 protected void Button1_Click(object sender, EventArgs e) { //默认查询所有,返回的是Table类型,转换成IQueryAble类型 ...
- 【Gym 100015B】Ball Painting
题 There are 2N white balls on a table in two rows, making a nice 2-by-N rectangle. Jon has a big pai ...
- Java编程思想学习(十四) 枚举
关键字enum可以将一组具名的值有限集合创建一种为新的类型,而这些具名的值可以作为常规的程序组件使用. 基本enum特性 调用enum的values()方法可以遍历enum实例,values()方法返 ...
- opencv笔记2:图像ROI
time:2015年 10月 03日 星期六 12:03:45 CST # opencv笔记2:图像ROI ROI ROI意思是Region Of Interests,感兴趣区域,是一个图中的一个子区 ...
- mysql中的having
from子句后面可以用where选择行,group by子句后面可以用having子句选择行, having中条件的定义和where中很相似,但是having中可以直接用聚合函数,但是where中不能 ...
- nopCommerce 安装失败: 引发类型为“System.OutOfMemoryException”的异常。
如果你在安装nopCommerce 3.00版本的时候报如上异常,解决方案: 1.在服务器上检查内存是否已经满了,因为nopCommerce 在安装的时候需要很多内存. 2.关闭占用内存大的进程,保证 ...
- newinstance和new有什么区别
用newInstance与用new是区别的,区别在于创建对象的方式不一样,前者是使用类加载机制,那么为什么会有两种创建对象方式?这个就要从可伸缩.可扩展,可重用等软件思想上解释了.Java中工厂模式经 ...
- 活用scanf
scanf()是C语言中用于读入格式化数据(formatted data)的函数. 我们可能对scanf()的一般用法已经了然,而至于scanf()读入数据的机制恐怕并不十分清楚. 下面我将比较详细地 ...
- 微信公众平台开发接口PHP SDK完整版
<?php /* 方倍工作室 http://www.fangbei.org/ CopyRight 2015 All Rights Reserved */ define("TOKEN&q ...
- jQuery中prop()函数控制多选框(全选,反选)
今天看了jQuery手册,对prop()函数又多了一点认识,记忆力不好,记录下来. prop() : 获取匹配元素集中第一个元素的值 判断checkbox中的第一个是否被选中: $(":ch ...