初学多线程编程

一、线程概述

进程是系统中程序执行和资源分配的基本单位,之所以有了进程还要引入线程有几个方面原因:

1、和进程相比,线程是一种非常“节俭”的多任务操作方式。运行于一个进程中的多个线程,它们共用地址空间,而且线程彼此切换所需的时间远远小于进程间切换所需的时间。

2、线程间方便的通信机制。对于进程来说,它们具有独立的数据空间,进行数据传递只能通过进程间通信方式进行。线程由于在同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,快捷而且方便。

3、多线程程序作为一种多任务、并发的工作方式,有很多优点。

在编写Linux下的多线程程序,需要使用头文件pthread.h,连接需要使用库libpthread.h,因为pthread的库不是Linux系统的库,所以编译的时候要加上"-lpthread"。

二、线程基本编程

创建线程实际上就是确定调用该线程函数的入口点,通常使用的函数是pthread_create()。其函数语法要点如下:

在线程创建以后,开始运行相关的线程函数,运行完后线程也就退出了,这是一种方式。另一种方式是使用函数pthread_exit(),这是线程的主动行为,但是要注意不能随意使用exit()进行出错处理,因为exit()会使整个进程终止,这样该进程包含的多个线程都会被终止,所以只能使用pthread_exit(),其函数语法要点如下:

由于一个进程的多个线程是共享数据段,因此通常在线程退出后,它所占用的资源并不会随着线程的终止而得到释放。这时候需要使用pthread_join()函数,它会将当前线程挂起来等待线程的结束,这是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回,其函数语法要点如下:

线程终止有两种情况:正常终止和非正常终止。线程主动调用pthread_exit或者从线程函数中return都将使线程正常退出,这是可预见的退出方式;非正常终止是线程在其他线程干预下,或者由于自身运行出错而退出,这种退出方式是不可预见的。不论是何种方式,都存在资源释放的问题,如何保证线程终止时顺利释放自己占用的资源,是一个必须解决的问题。从pthread_cleanup_push的调用点到pthread_cleanup_pop之间的程序段中的终止动作(注意:包括调用pthread_exit()和异常终止,但是不包括return)都将执行pthread_cleanup_push()所指定的清理函数。两个函数语法要点如下:

#include <pthread.h>

void pthread_cleanup_push(void(*rtn)(void *),void *arg)

将清除函数压入清除栈(这里注意栈特点是后入先出)

rtn:清除函数

arg:清除函数的参数

#include <pthread.h>

void pthread_cleanup_pop(int execute)

将清除函数弹出清除栈

参数execute的值决定执行到pthread_cleanup_pop()时是否在弹出清理函数的同时执行该函数,非0:执行;0:不执行。

三、线程之间的同步和互斥

进行多线程编程,因为无法知道哪个线程会在哪个时候对共享资源进行操作,所以应该保护共享资源,解决线程之间对资源的竞争有三种办法:互斥量(Mutex)、信号灯(Semaphore)和条件变量(Conditions)。

主要对比一下互斥量和信号量:

*互斥量是一把钥匙,一个人拿了就可进入一个房间,出来的时候把钥匙交给等待队列的第一个。

*信号量是一个可容纳N人的房间,人不满就可以进去,人满了就等待有人出来。

*互斥量要由获得锁的线程来释放,而信号量可以由其他线程释放。

*初始状态可能不一样:mutex初始为1,而信号量的初始值可能是0或者1。

1、互斥锁线程控制

互斥锁是用一种简单的加锁方法控制对共享资源的原子操作。它只有两种状态,就是上锁和解锁,在同一时间只有一个线程掌握某个互斥锁。若其他线程希望上锁一个已经被锁上的互斥锁,则该进程就会挂起,直到上锁的线程释放掉互斥锁为止。可以说,这把互斥锁保证每个线程对共享资源按顺序进行原子操作。

互斥锁包括几个基本函数:

*互斥锁初始化:pthread_mutex_init()

*互斥锁上锁:pthread_mutex_lock()

*互斥锁解锁:pthread_mutex_unlock()

*清除互斥锁:pthread_mutex_destroy()

各函数语法要点如下:

 

2、信号量线程控制

信号量也就是操作系统中用到的PV原子操作,广泛用于进程或者线程的同步与互斥。信号量本质是一个非负整数计数器,用来控制对公共资源的访问。当信号量用于同步操作时,往往会设置多个信号量,并安排不同的初始值来实现它们之间的顺序执行。若用于互斥,几个进程或者线程往往只设置一个信号量sem。

sem_init()用于创建一个信号量,并初始化它的值,语法要点如下:

sem_wait()和sem_trywait()相当于P操作(减1),当信号量大于0时都将信号量的值减1,区别是前者会阻塞,后者立即返回。

sem_post()相当于V操作,将信号量的值加1同时发出信号唤醒等待的线程。

sem_getvalue()用于取得信号量的值。

sem_destroy()用于删除信号量。

函数语法要点如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值