linux多线程编程实例_linux线程调度策略

(1) 2024-07-29 15:23

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
linux多线程编程实例_linux线程调度策略,希望能够帮助你!!!。

一、线程理论基础

线程技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者。传统的Unix也支持线程的概念,但在一个进程中只允许有一个线程,这样多线程就意味着多进程。现在,多线程技术已经被许多操作系统所支持,包括Windows/NT、Linux。

有了进程,还要引入线程的原因:

(1)和进程相比,线程是一种非常节俭的多任务操作方式。在Linux系统下,启动一个新的进程必须分配给他独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种“昂贵”的多任务工作方式

(2)线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过进程间通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。

线程的优点

运行于一个进程中的多个进程,它们之间使用相同的地址空间,而且线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,一个进程的开销大约是一个线程开销的30倍左右。

多线程程序作为一种多任务、并发的工作方式,有如下优点:

使多CPU系统更加有效。操作系统会保证当前线程数不大于CPU数目时,不同的线程运行于不同的CPU上。

改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。

ps:线程需要CPU支持;线程由进程创建

多线程

Linux系统下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用libpthread.a

二、多线程程序设计

pthread_create()  创建一个工作线程

pthread_exit()      退出到主线程

pthread_join()      线程等待(只能等待一个)

exit(-1)   结束一个进程内所有线程

创建

#include<pthread.h> 

int pthread_create(pthread_t * tidp,const pthread_attr_t*attr,void*(*start_rtn)(void),void * arg)

tidp:线程id

attr:线程属性(通常为空) +NULL意味着所创建的线程为默认属性

start_rtn:线程要执行的函数

arg:start_rtn的参数

编译

因为pthread的库不是linux系统的库,所以在进行编译的时候要加上-lpthread

例: gcc filename -lpthread

终止线程

如果进程中任何一个线程中调用exit或_exit,那么整个进程都会终止。线程的正常退出方式有:

(1)线程从启动例程中返回

(2)线程可以被另一个进程终止

(3)线程自己调用

线程退出

#include<pthread.h>

void pthread_exit(void * rval_ptr)

功能:终止调用线程

Rval_ptr:线程退出返回值的指针

线程等待

#include<pthread.h>

int pthread_join(pthread_t tid,void **rval_ptr)

功能:阻塞调用线程,直到指定的线程终止。

Tid:等待退出的线程id

Rval_ptr:线程

三、线程同步

按顺序执行即“同步”

进行多线程编程,因为无法知道哪个线程会在那个时候对共享资源进行操作,因此让如何保护共享资源变得复杂,通过下面这些技术的使用,可以解决

线程之间对资源的竞争

1、互斥量Mutex

需要互斥量的原因:

例:Item * p =queue_list;

       Queue_list=queue_list->next;

       process_job(p);

       free(p);      

当线程1处理完Item *p=queue_list后,系统停止线程1的运行,改而运行线程2。线程2照样取出头节点,然后进行处理,最后释放了该节点。过了段时间,线程1重新得到运行。而这个时候,p所指向的节点已经被线程2释放掉,而线程1对此毫无知晓。他会接着运行process_job(p)。而这将导致无法预料的后果

对于这种情况,系统给我们提供了互斥 量.线程在取出头节点前必须要等待互斥量,如果此时有其他线程已经获得该互斥量,那么该线程将会阻塞在这里.只有等到其他线程释放掉该互斥量后,该线程才有可能得到该互斥量。互斥量从本质上说就是一把锁, 提供对共享资源的保护访问

创建互斥锁:

int pthread_mutex_init(pthread_mutex_t、*mutex,const pthread_mutexattr_t * attr)

pthread_mutex_timed_np:普通锁,同一线程锁多次

pthread_mutex_recursive_np:嵌套锁

pthread_mutex_errorcheck_np:检错锁

pthread_mutex_adaptive_np:适应锁

在Linux中,互斥量使用类型pthread_mutex_t表示。在使用前,要对它进行初始化

(1)对于静态分配的互斥量,可以将它设置为默认的mutex对象PTHREAD_MUTEX_INITIALIZER

(2)对于动态分配的互斥量,在申请内存(MALLOC)之后, 通过pthread_mutex_init进行初始化, 并且在释放内存(free)前需要调用pthread_mutex_destroy

示例代码:

#include <pthread.h>  

int pthread_mutex_init(pthread_mutex_t 、*mutex,const pthread_mutexattr_t *attr)  

int pthread_mutex_destroy(pthread_mutex_t *mutex)

加锁:

对共享资源的访问, 要使用互斥量进行加锁, 如果互斥量已经上了锁, 调用线程会阻塞, 直到互斥量被解锁。

int pthread_mutex_lock(pthread_mutex_t * mutex)

int pthread_mutex_trylock(pthread_mutex_t * mutex)

返回值: 成功则返回0, 出错则返回错误编号。     trylock是非阻塞调用模式, 如果互斥量没被锁住, trylock函数将对互斥量加锁, 并获得对共享资源的访问权限; 如果互斥量被锁住了,trylock函数将不会阻塞等待而直接返回EBUSY, 表示共享资源处于忙状态

对共享资源的访问,要使用互斥量进行加锁,如果互斥量已经上了锁

处理:

解锁:

在操作完成后,必须给互斥量解锁,也就是前面所说的释放。这样其他等待该锁的线程才有机会获得该锁,否则其他线程将会永远阻塞。

示例代码:int pthread_mutex_unlock(pthread_mutex_t *mutex)

销毁:int pthread_mutex_destory(pthread_mutex_t * mutex)

互斥量与信号量

Mutex是一把钥匙,一个人拿了就可进入一个房间,出来的时候把钥匙交给队列的第一个。    

Semaphore是一件可以容纳N人的房间,如果人不满就可以进去,如果人满了,就要等待有人出来。    对于N=1的情况,称为binary semaphore。

Binary semaphore与Mutex的差异:

1. mutex要由获得锁的线程来释放(谁获得,谁释放)。而semaphore可以由其它线程释放

2. 初始状态可能不一样:mutex的初始值是1 ,semaphore的初始值可能是0(或者为1)

2、信号灯Semaphore

3、条件变量Conditions

(1)创建条件变量

pthread_cond_t  cond; 

(2)条件变量初始化

a、静态初始化       PTHREAD_COND_INITIALIZER      

b、动态初始化       int pthread_cond_init(pthread_cond_t * cond, pthread_condattr_t * cond_attr);

(3)条件变量撤销

int pthread_cond_destory(pthread_cond_t * cond);

(4)条件变量等待

int pthread_cond_wait(pthread_cond_t * cond,pthread_mutex_t * mutex);

unlock->wait->lock

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

上一篇

已是最后文章

下一篇

已是最新文章

发表回复