首页 > 编程知识 正文

linux多线程服务器编程,linux多线程编程

时间:2023-05-05 14:25:37 阅读:175803 作者:4893

阅读《Unix/Linux系统编程》的Pthread相关内容,调查并总结相关资料

本文介绍了Pthread多线程的基本操作和互斥量的基本操作

1. POSIX和Pthread线程的概念1.1 POSIX: POSIX表示3358 www.Sina.com/(可移植性系统接口,简称POSIX ) )

一般来说,可移植操作系统接口API定义了APP应用程序使用的一组编程接口。 它们可以实现为调用单个系统,也可以通过调用多个系统来实现,但完全不使用系统调用也没有问题。 实际上,**API在各种操作系统中实现,为APP应用程序提供完全相同的接口,但**API本身可能在这些系统中实现。

例如,对于某个系统调用函数,Linux是funcA (),Windows是funcB ) )函数,这提供了源代码级别的可移植性。 要将此程序从Linux移植到Windows,必须将其替换为源代码中的所有funcA () (函数都是funcB ) )函数并重新编译。

posix标准的出现是为了解决这个问题。 linux和windows必须实现基本的posix标准。 linux将funcA函数封装在posix_func中,windows将funcB函数也封装在posix_func中,以便在不同的操作系统开发中调用posix_func函数。 程序为http://WWWWN

1.2 Pthread英语: POSIX Threads,常被缩写为Pthreads。应用程序通过应用编程接口(API)而不是直接通过系统调用来编程(即并不需要和内核提供的系统调用来编程)

实现POSIX线程标准的库通常称为在源代码级别可移植了,Pthreads定义了在pthread.h头文件和线程库中实现的一组c语言类型、函数和常量。

Pthreads API大约有100个函数调用,全部以pthread_开头

2. pthread函数API 2.1 .线程pthread_create (函数intpthread_create ) pthread_t*pthread_id,constpthread_attr_t

参数说明:

pthread_id :

此参数指向pthread_t类型(线程标识符类型),并将新分配的是POSIX的线程标准,定义了创建和操纵线程的一套API分配给指针指向的内容。 在Linux上,pthread_id类型为unsigned long int。 可以通过pthread_self ()函数获取自己的线程ID。

phread_tpthread_self(void ) attr :

此参数用于设置线程属性,pthread_attr_t是线程属性类型。 在使用此类型的变量之前,必须初始化并在使用后释放资源。

定义pthread属性变量pthread_attr_t attr,用pthread_attr_init(attr )初始化线程属性变量,设置线程属性,然后传递给pthread_create函数

pthread_attr_t attr; //定义线程属性类型变量pthread_attr_init(attr )//初始化此变量的pthread _ attr _ setdetachstate (attr,pthread _ create _ ste //设置线程属性-阻止线程连接到其他线程的pthread_create(id、attr、func、NULL ); //根据线程属性创建新线程pthread_attr_destroy(attr ); //释放线程资源如果此参数为NULL,则建议使用NULL传递参数,除非需要更改Pthreads线程属性。

pthread_create(id,NULL,func,NULL ); func:

线程执行函数的开始地址。

arg :

执行函数的参数。

2.2线程比较函数pthread_equal可以通过所分配的唯一线程ID来区分线程,但不应该直接比较线程ID (

unsigned int,而在FreeBSD上用的是结构体指针。 所以不能直接使用==判断),而应该使用pthread_equal()函数对它们进行比较

int pthread_equal(pthread_t thread1, pthread_t thread2)

如果线程相同返回非0,线程不同返回0

2.3 线程终止函数pthread_exit void pthread_exit(void * status)

显式的终止线程。status是线程退出状态,0代表正常终止,非0表示异常终止。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。并且thread指定的线程必须是joinable的。

2.4 线程连接函数pthread_join int pthread_join(pthread_t thread, void **__thread_return)

阻塞的方式等待thread指定的线程结束,并将终止线程的退出状态保存在__thread_return中

成功返回0, 失败返回错误号。

3. pthread简单案例:

通过多线程计算矩阵所有元素和:每一个线程计算一行元素的和,最终结果合并到主线程内

matrixTest.c

#include <stdio.h>#include <pthread.h>//矩阵大小:4X4#define MAT_LINENUM 4//矩阵每个元素大小int mat[][MAT_LINENUM] = { {1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,16}};//记录矩阵每一行的和int sum[MAT_LINENUM];//线程入口函数void* sumCalc(void* arg){ printf("this is sub thread: id is %ldn",pthread_self()); long row = (long)arg; printf("my mission is calc the sum of row %ldn",row); int ans = 0; for(int i = 0 ; i < MAT_LINENUM ; ++i){ ans += mat[row][i]; } sum[row] = ans; printf("the row %ld calc down, the sum of row is %dn",row,ans); pthread_exit((void*)0);//线程正常终止}int main(){ pthread_t idArr[MAT_LINENUM]; pthread_t mainId = pthread_self(); printf("this is main thread: id is %ldn",mainId); for(long i = 0 ; i < MAT_LINENUM ; ++i){ //创建线程 pthread_create(&idArr[i],NULL,sumCalc,(void*)i); } for(int i = 0 ; i < MAT_LINENUM ; ++i){ void* status; //阻塞的等待线程结束 pthread_join(idArr[i],&status); } int ans = 0; for(int i = 0 ; i < MAT_LINENUM ; ++i){ ans += sum[i]; } printf("nthe sum of matrix is %dn",ans);}

运行结果:

xtark@xtark-vmpc:~/桌面/linux_study/section4/pthread test$ gcc matrixTest.c -lpthreadxtark@xtark-vmpc:~/桌面/linux_study/section4/pthread test$ ./a.out this is main thread: id is 140126291924736this is sub thread: id is 140126283749120my mission is calc the sum of row 0the row 0 calc down, the sum of row is 10this is sub thread: id is 140126266963712my mission is calc the sum of row 2the row 2 calc down, the sum of row is 42this is sub thread: id is 140126275356416my mission is calc the sum of row 1the row 1 calc down, the sum of row is 26this is sub thread: id is 140126258571008my mission is calc the sum of row 3the row 3 calc down, the sum of row is 58the sum of matrix is 136 4. Pthread互斥量

Pthread中的锁即为互斥量,意思是相互排斥。可以通过互斥量来保证在任一时刻,只有一个线程能够访问该对象。互斥量可以用于线程同步:线程同步是指多线程通过特定的东西(如互斥量)来控制线程之间的执行顺序(同步),也可以说是在线程之间通过同步建立起执行顺序的关系,如果没有同步那线程之间是各自运行各自的。

4.1 互斥量的初始化

Pthread中的互斥量即为pthread_mutex_t类型,在使用该类型前必须对其进行初始化。有两种方法:

静态方法:定义互斥量m,并使用默认属性对其初始化

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

动态方法:使用pthread_mutex_init()函数来对pthread_mutex_t变量进行初始化,通过第二个参数设置互斥量属性。第二个参数可以设置为NULL来使用默认属性初始化互斥量

int pthread_mutex_init(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__mutexattr) pthread_mutex_init(&m,NULL); 4.2 互斥量的上锁解锁

互斥量初始化完成后使用通过以下方法对互斥量进行上锁、解锁等操作。

临界区:指的是一个访问共用资源的程序片段,而这些共用资源又无法同时被多个线程访问。当有线程进入临界区段时,其他线程必须等待。在Pthread中,互斥量用于保护临界区,以确保临界区内在任一时刻最多只能有一个线程。

上锁函数:给一个互斥量上锁,如果该互斥量处于解锁状态就给互斥量上锁并继续向下执行。如果该互斥量处于上锁状态则阻塞并在互斥量的等待队列中等待,直到获得该锁。

int pthread_mutex_lock(pthread_mutex_t *__mutex)

解锁函数:解锁互斥量,退出临界区。

int pthread_mutex_unlock(pthread_mutex_t *__mutex)

互斥量销毁函数:

int pthread_mutex_destroy(pthread_mutex_t *__mutex)

死锁预防:可以使用条件加锁函数pthread_mutex_trylock()预防死锁。如果互斥量已被加锁,则pthread_mutex_trylock不阻塞并返回一个值来描述互斥锁的状况。如果互斥量处于解锁状态,则与pthread_mutex_lock一样对互斥量加锁

int pthread_mutex_trylock(pthread_mutex_t *__mutex) 4.3 互斥量使用示例

创建100线程,每个线程对int类型全局变量+1000,在主线程中返回最终结果。

不适用互斥量时:

#include <pthread.h>#include <stdio.h>#define N 100int num;//线程入口函数void* func(void* arg){ for(int i = 0 ; i < 1000 ; ++i){ num++; }}int main(){ pthread_t threadId[N];//保存线程标识符 for(int i = 0 ; i < N ; ++i){ pthread_create(&threadId[i],NULL,func,NULL);//创建多个线程 } for(int i = 0 ; i < N ; ++i){ void * status; pthread_join(threadId[i],&status);//阻塞的等待线程结束 } printf("the num is %dn",num);}

运行结果:最后结果为97066而不是100000,可见出现了线程同步问题。可以引入互斥量加以解决

xtark@xtark-vmpc:~/桌面/linux_study/section4/pthread test$ gcc mutexTest.c -lpthreadxtark@xtark-vmpc:~/桌面/linux_study/section4/pthread test$ ./a.out the num is 97066

使用互斥量时:

#include <pthread.h>#include <stdio.h>#include <stdlib.h>#define N 100pthread_mutex_t * m;//指向互斥量变量的指针int num;void* func(void* arg){ for(int i = 0 ; i < 1000 ; ++i){ pthread_mutex_lock(m);//上锁 num++; pthread_mutex_unlock(m);//解锁 }}int main(){ m = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));//为互斥量变量分配内存空间 pthread_mutex_init(m,NULL);//初始化互斥量 pthread_t threadId[N]; for(int i = 0 ; i < N ; ++i){ pthread_create(&threadId[i],NULL,func,NULL);//创建多个线程 } for(int i = 0 ; i < N ; ++i){ void * status; pthread_join(threadId[i],&status);//阻塞的等待多个线程结束 } printf("the num is %dn",num);}

运行结果:输出100000,正确

xtark@xtark-vmpc:~/桌面/linux_study/section4/pthread test$ gcc mutexTest.c -lpthreadxtark@xtark-vmpc:~/桌面/linux_study/section4/pthread test$ ./a.out the num is 100000

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。