多线程

使用多线程好处:

一、通过为每种事件类型的处理单独分配线程,可以简化处理异步事件的代码,线程处理事件可以采用同步编程模式,启闭异步编程模式简单

二、方便的通信和数据交换

由于进程之间具有独立的数据空间,多进程必须使用操作系统提供的复杂机制才能实现内存和文件描述符的共享,导致上下文切换的开销比较大。而线程之间共享进程的所有资源,所以,多线程可以访问相同的存储空间和文件描述符。

三、对一些不具有互斥型的问题,可以将其分解为从而改善程序的吞吐量。对于进程,在完成多个任务时,实际上需要将任务串行化。对于多线程,相互独立而且想不不依赖的任务可以交叉运行,只需要为每个任务分配一个线程即可。

四、交互的程序可以通过使用多线程实现响应时间的改善,多线程可以把程序中用于处理用户输入输出的部分与其他部分分开。

线程包含了进程内执行环境必须的信息,包括进程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多线程编程——多线程与线程同步的更多相关文章

  1. 《Linux多线程服务端编程》笔记——线程同步精要

    并发编程基本模型 message passing和shared memory. 线程同步的四项原则 尽量最低限度地共享对象,减少需要同步的场合.如果确实需要,优先考虑共享 immutable 对象. ...

  2. Linux系统编程@多线程编程(一)

    多线程编程 涉及操作系统原理概念 时间片 进程状态 上下文: 对进程来说,就是进程的执行环境,具体就是各个变量和数据,包括所有的寄存器变量.打开的文件.内存信息等. 进程的写时复制:由于一般 fork ...

  3. Linux系统编程@多线程编程(二)

    线程的操作 线程标识 线程的ID表示数据类型:pthread_t (内核中的实现是unsigned long/unsigned int/指向pthread结构的指针(不可移植)几种类型) 1.对两个线 ...

  4. 多线程编程-- part 2 线程的生命周期和优先级

    线程的创建到消亡的历程: java多线程的5种状态: (1)New(新建) new Thread(run()) 该线程还没开始运行,状态是new,在程序运行前还有一些基础工作要做 (2)runnabl ...

  5. iOS多线程编程之创建线程安全(转载)

    一.多线程的安全隐患 资源共享 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象.同一个变量.同一个文件 当多个线程访问同一块资源时,很容易引发数据错乱和数 ...

  6. java多线程(2) 线程同步

    我们对线程访问同一份资源的多个线程之间,来进行协调的这个东西,就是线程同步.   例子1:模拟了多个线程操作同一份资源,可能带来的问题: package com.cy.thread; public c ...

  7. Python多线程(2)——线程同步机制

    本文介绍Python中的线程同步对象,主要涉及 thread 和 threading 模块. threading 模块提供的线程同步原语包括:Lock.RLock.Condition.Event.Se ...

  8. java多线程编程(二创建线程)

    1.概念           因为java是完全面向对象的,所以在java中,我们说的线程,就是Thread类的一个实例对象.所以,一个线程就是一个对象,它有自己字段和方法. 2.创建线程 创建线程有 ...

  9. C#多线程:深入了解线程同步lock,Monitor,Mutex,同步事件和等待句柄(中)

    本篇继续介绍WaitHandler类及其子类 Mutex,ManualResetEvent,AutoResetEvent的用法..NET中线程同步的方式多的让人看了眼花缭乱,究竟该怎么去理解呢?其实, ...

随机推荐

  1. zabbix 乱码的问题

    文章转自:http://www.ttlsa.com/zabbix/zabbix-chinese-garbled-ttlsa/ 在使用zabbix的时候发现图片下方的中文都是一个个小方格 这是zabbi ...

  2. MVC2 Area实现网站多级目录

    Areas是ASP.NET Mvc 2.0版本中引入的众多新特性之一,它可以帮你把一个较大型的Web项目分成若干组成部分,即Area.实现Area的功能可以有两个组织形式: 在1个ASP.NET Mv ...

  3. 在 Visual Studio 2013 中创建 ASP.NET Web 项目(0):专题导航 [持续更新中]

    写在前面的话 随着 Visual Studio 2013 的正式推出,ASP.NET 和 Visual Studio Web 开发工具 也发布了各自的最新版本. 新版本在构建 One ASP.NET ...

  4. startsWith

    if (!String.prototype.startsWith) { Object.defineProperty(String.prototype, 'startsWith', { enumerab ...

  5. sql-in/not in和exists/not exists的区别

    In和Exists的区别 这两个函数是差不多的,但由于优化方案不同,通常NOT Exists要比NOT IN要快,因为NOT EXISTS可以使用结合算法二NOT IN就不行了,而EXISTS则不如I ...

  6. Netbeans 中的编译器相关配置

    gcc-core:C 编译器 gcc-g++:C++ 编译器 gdb:GNU 调试器 make:"make" 实用程序的 GNU 版本

  7. 【HDU 5363】Key Set

    题 Description soda has a set $S$ with $n$ integers $\{1, 2, \dots, n\}$. A set is called key set if ...

  8. Linux/Unix System Level Attack、Privilege Escalation(undone)

    目录 . How To Start A System Level Attack . Remote Access Attack . Local Access Attack . After Get Roo ...

  9. CF Gym 100685A Ariel

    传送门 A. Ariel time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...

  10. java 线程---成员变量与局部变量

    关于成员变量与局部变量: 如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作时,他们对该成员变量是彼此影响的(也就是说一个线程对成员变量的改变会影响到另一个线程) . 如果一个变量是局 ...