Linux多线程编程问题

Linux 多线程编程问题1重入问题传统的UNIX没有太多考虑线程问题,库函数里过多使用了全局和静态数据,导致严重的线程重入问题。

1.1–D_REENTRANT /-pthread和errno的重入问题。

所先UNIX的系统调用被设计为出错返回-1,把错误码放在errno中(更简单而直接的方法应该是程序直接返回错误码,或者通过几个参数指针来返回)。

由于线程共享所有的数据区,而errno是一个全局的变量,这里产生了最糟糕的线程重入问题。

比如:do {bytes = recv(netfd, recvbuf, buflen, 0);} while (bytes != -1 && errno != EINTR);在上面的处理recv被信号打断的程序里。

如果这时连接被关闭,此时errno应该不等于EINTR,如果别的线程正好设置errno为EINTR,这时程序就可能进入死循环。

其它的错误码处理也可能进入不可预测的分支。

在线程需求刚开始时,很多方面技术和标准(TLS)还不够成熟,所以在为了解决这个重入问题引入了一个解决方案,把errno定义为一个宏:extern int *__errno_location (void);#define errno (*__errno_location())在上面的方案里,访问errno之前先调用__errno_location()函数,线程库提供这个函数,不同线程返回各自errno的地址,从而解决这个重入问题。

在编译时加-D_REENTRANT就是启用上面的宏,避免errno重入。

另外-D_REENTRANT还影响一些stdio的函数。

在较高版本的gcc里,有很多嵌入函数的优化,比如把printf(“Hello\n”);优化为puts(“hello\n”);之类的,有些优化在多线程下有问题。

所以gcc引入了–pthread 参数,这个参数出了-D_REENTRANT外,还校正一些针对多线程的优化。

因为宏是编译时确定的,所以没有加-D_REENTRANT编译的程序和库都有errno重入问题,原则上都不能在线程环境下使用。

不过在一般实现上主线程是直接使用全局errno变量的,也就是__errno_location()返回值为全局&errno,所以那些没加-D_REENTRANT编译的库可以在主线程里使用。

这里仅限于主线程,有其它且只有一个固定子线程使用也不行,因为子线程使用的errno地址不是全局errno变量地址。

对于一个纯算法的库,不涉及到errno和stdio等等,有时不加_REENTRANT也是安全的,比如一个纯粹的加密/解谜函数库。

比较简单的判断一个库是否有errno问题是看看这个库是使用了errno还是__errno_location():readelf -s libxxx.so | grep errno另外一个和errno类似的变量是DNS解析里用到的h_errno变量,这个变量的重入和处理与errno一样。

这个h_errno用于gethostbyXX这个系列的函数。

1.2库函数重入早期很多unix函数设计成返回静态buffer。

这些函数都是不能重入的。

识别这些函数有几个简单的规则:1.2.1stdio函数是可以重入的。

这是因为stdio函数入口都会调用flockfile()锁定FILE。

另外stdio也提供不锁定(非重入)的函数,这些函数以_unlock结尾,具体参见man unlocked_stdio。

利用这些特性可以做到多个stdio的互斥操作。

如:flockfile(fp);fwrite_unlocked(rec1, reclen1, 1, fp);fwrite_unlocked(rec2, reclen2, 1, fp);funlockfile(fp);1.2.2返回动态分配数据的函数,这些一般是可以重入的。

这些函数的特点是返回的指针需要显式释放,用free或者配对的释放函数。

如:getaddrinfo /freeaddrinfomalloc/strdup/calloc/freefopen/fdopen/popen/fcloseget_current_dir_name/freeasprintf/vasprintf/freegetline/getdelim/freeregcomp/regfree1.2.3函数返回一个和输入参数无关的数据,而且不需要free的大部分情况下是不可重入的。

如gmtime, ntoa, gethostbyname…1.2.4函数依赖一个全局数据,在多次或者多个函数间维护状态的函数是不可重入的。

如getpwent, rand…1.2.5带有_r变体的函数都是不可重入的。

这些函数大部分是上面两类的。

这些变体函数是可重入的代替版本。

可以用下面命令查看glibc有多少这种函数:readelf -s /lib/libc.so.6 | grep _r@这些函数名有很大一部分是getXXbyYY, getXXid, getXXent, getXXnam1.2.6rand,lrand48系列随机数不可重入的原因在于这些函数使用一个全局的状态,并且都有相应的_r变体。

重入这些非线程安全的函数不会有稳定性问题,不过会导致随机数不随机(可预测)。

在要求比较严格的随机数应用里,建议用/dev/random和/dev/urandom,这两个设备的不同在于前者读出的数据理论上是绝对随机的,在系统无法提供足够随机数据时读会阻塞。

后者只是提供尽量随即的数据,随机度不够时用算法生成伪随机数来代替,所以不会阻塞。

1.2.7不可重入函数处理。

对大部分不可重入函数可以使用对应的_r变体。

有些函数可能没有对应_r变体,可以选用类似功能的函数替换。

如:inet_ntoa inet_ntopctime → strftime, asctime, localtime_r+sprintfgethostbyname, getservbyname → getaddrinfo1.2.8用其它代码/逻辑替换不可重入代码1.2.9有些库有两个版本,带和不带_r/_mt/th等后缀的,多线程一般用带后缀的版本的库。

1.3应用程序的线程安全1.3.1全局量/共享资源互斥访问1.3.2相关数据原子操作1.3.3操作顺序2互斥逻辑同步逻辑不仅仅是多线程程序的问题,在多进程环境里也经常使用。

同步逻辑有很多种,其中最常用的就是互斥逻辑,也就是锁。

由于历史原因,LINUX下产生了好多锁定API,下面列个简单的表格:2.1Fcntl文件锁2.1.1支持偏移量。

也就是可以用一个文件模拟许多互斥锁。

2.1.2进程锁非线程锁。

也就是线程之间无法互斥。

老的2.4 kernel没有支持这个POSIX标准,所以可以跨线程使用。

2.1.3相关句柄关闭导致文件解锁。

这个锁是按进程+文件定位的,也就是同一进程打开多次文件使用相同的锁定关系。

即使只关闭其中一个句柄导致解锁。

在2.4 kernel下也有这个问题,任何线程关闭对应文件句柄,不是导致该线程解锁,而是导致所有线程解锁。

2.1.4逻辑死锁检测。

2.2Flock文件锁2.2.1按句柄锁定2.2.2进程的句柄继承2.3SYSV semaphore2.3.1信号量。

2.3.2性能比文件锁要好。

2.3.3可以同时对多个信号量进行复合操作2.3.4/proc/sys/kernel/sem: SEMMSL SEMMNS SEMOPM SEMMNI2.3.4.1SEMMSL, 每个信号量ID里的最大信号量数2.3.4.2SEMMNS, 系统总信量灯数,小于SEMMSL x SEMMNI2.3.4.3SEMOPM, 每次semop最大操作个数2.3.4.4SEMMNI, 信号量ID数2.3.5高版kernel有等待超时机制#include <unistd.h>#include <asm/unistd.h>#ifndef SEMTIMEDOP#define SEMTIMEDOP 4#endifstatic inlineint semtimedop(int semid, struct sembuf *sops, unsigned nsops, struct timespec *timeout){return syscall(__NR_ipc, SEMTIMEDOP, semid, nsops, 0, sops, timeout);}2.4Mutex和rwlock2.4.1在非竞争下性能最好2.4.2NPTL使用futex实现,竞争条件下性能也不错。

Linuxthread在竞争时由管理线程仲裁,开销较大。

2.4.3无crash自动解锁机制2.4.4有等待超时机制2.5内存原子操作2.5.1内存原子操作是多CPU系统里最基本的互斥操作。

所有的其它逻辑都是建立这之上的。

2.5.2整数操作,操作书为一个int类型。

有些非x86的CPU只支持到24位值。

#include <asm/atomic.h>atomic_t value;int v;v=atomic_read(&value);atomic_set(&value, v);atomic_add(v, &value);atomic_sub(v, &value);atomic_sub_and_test(v, &value); /*返回结果是否为0*/atomic_inc(&value);atomic_dec(&value);atomic_dec_and_test(&value); /*返回结果是否为0*/atomic_inc_and_test(&value); /*返回结果是否为0*/atomic_set_mask(mask, &value);atomic_clear_mask(mask, &value);2.5.3bitmap位图操作#include <asm/bitops.h>void * bitmap;int nr;set_bit(nr, bitmap); /* OR */clear_bit(nr, bitmap); /* AND ~ */change_bit(nr, bitmap); /* XOR */test_bit(nr, bitmap);test_and_set_bit(nr, bitmap); /* 返回旧值*/test_and_clear_bit(nr, bitmap); /* 返回旧值*/test_and_change_bit(nr, bitmap); /* 返回新值*/这些函数前面可以加两个下划线__表示非原子操作。

合集下载

Unix_Linux_Windows_OpenMP多线程编程

Unix_Linux_Windows_OpenMP多线程编程

Unix_Linux_Windows_OpenMP多线程编程第三章 Unix/Linux 多线程编程[引言]本章在前面章节多线程编程基础知识的基础上,着重介绍 Unix/Linux 系统下的多线程编程接口及编程技术。

3.1 POSIX 的一些基本知识POSIX 是可移植操作系统接口(Portable Operating SystemInterface)的首字母缩写。

POSIX 是基于 UNIX 的,这一标准意在期望获得源代码级的软件可移植性。

换句话说,为一个 POSIX 兼容的操作系统编写的程序,应该可以在任何其它的 POSIX 操作系统(即使是来自另一个厂商)上编译执行。

POSIX 标准定义了操作系统应该为应用程序提供的接口:系统调用集。

POSIX是由 IEEE(Institute of Electrical andElectronic Engineering)开发的,并由 ANSI(American National Standards Institute)和 ISO(International StandardsOrganization)标准化。

大多数的操作系统(包括 Windows NT)都倾向于开发它们的变体版本与 POSIX 兼容。

POSIX 现在已经发展成为一个非常庞大的标准族,某些部分正处在开发过程中。

表 1-1 给出了 POSIX 标准的几个重要组成部分。

POSIX 与 IEEE 1003 和 2003 家族的标准是可互换的。

除 1003.1 之外,1003 和 2003 家族也包括在表中。

管理 POSIX 开放式系统环境(OSE) 。

IEEE 在 1995 年通过了这项标准。

ISO 的1003.0版本是 ISO/IEC 14252:1996。

被广泛接受、用于源代码级别的可移植性标准。

1003.1 提供一个操作系统的C 语1003.1 言应用编程接口(API) 。

IEEE 和 ISO 已经在 1990 年通过了这个标准,IEEE 在1995 年重新修订了该标准。

解决多线程编程中的资源竞争问题

解决多线程编程中的资源竞争问题

解决多线程编程中的资源竞争问题多线程编程中的资源竞争问题是指多个线程同时对共享资源进行读写操作而产生的冲突。

资源竞争问题会导致数据不一致、死锁等严重后果,并且在多核处理器上,资源竞争问题还可能导致性能瓶颈。

为了解决多线程编程中的资源竞争问题,我们可以采取以下几种策略。

1.锁机制锁机制是最常用的解决资源竞争问题的方式之一。

通过在多个线程对共享资源进行读写操作时,加锁来保证同一时间只有一个线程可以访问共享资源,从而避免资源竞争问题的发生。

常见的锁机制包括互斥锁、读写锁、自旋锁等。

使用锁机制需要注意锁的粒度,过细的粒度可能导致性能问题,而过粗的粒度可能无法充分利用多线程的并发性能。

2.同步机制除了锁机制,还可以使用同步机制来解决资源竞争问题。

同步机制可以通过信号量、条件变量等方式来实现线程间的协作,以保证共享资源被安全地访问。

例如,可以使用条件变量来实现线程的等待和唤醒,以此来解决生产者-消费者模型中的资源竞争问题。

3.原子操作原子操作是不可中断的操作,能够确保多个线程对共享资源的操作是原子的。

在多线程编程中,可以使用原子操作来替代锁机制,从而避免显式地加锁和解锁的开销。

原子操作通常由处理器提供支持,使用原子操作可以有效地减少资源竞争问题的发生。

4.适当的数据结构选择在多线程编程中,选择合适的数据结构也可以减少资源竞争问题的发生。

例如,可以使用线程安全的队列、哈希表等数据结构,这些数据结构内部会使用锁、原子操作等方式来保证线程的安全访问。

5.数据复制在某些场景下,可以使用数据复制的方式来避免资源竞争问题。

即将共享资源的副本分别分配给每个线程,每个线程操作自己的副本而不影响其他线程的操作。

这种方式虽然会增加内存开销,但可以大大地减少资源竞争问题的发生,提高程序的并发性能。

6.异步编程异步编程是一种避免资源竞争问题的有效方式。

通过将任务切换为事件驱动的方式执行,可以避免多个线程对共享资源进行读写操作的竞争。

linux多线程 pthread常用函数详解

linux多线程 pthread常用函数详解

linux多线程pthread常用函数详解Linux多线程是指在Linux操作系统中运行的多个线程。

线程是执行程序的基本单位,它独立于其他线程而存在,但共享相同的地址空间。

在Linux中,我们可以使用pthread库来实现多线程程序。

本文将详细介绍pthread库中常用的函数,包括线程的创建、退出、同步等。

一、线程创建函数1. pthread_create函数pthread_create函数用于创建一个新线程。

其原型如下:cint pthread_create(pthread_t *thread, const pthread_attr_t *attr, void*(*start_routine) (void *), void *arg);参数说明:- thread:用于存储新线程的ID- attr:线程的属性,通常为NULL- start_routine:线程要执行的函数地址- arg:传递给线程函数的参数2. pthread_join函数pthread_join函数用于等待一个线程的结束。

其原型如下:int pthread_join(pthread_t thread, void retval);参数说明:- thread:要等待结束的线程ID- retval:用于存储线程的返回值3. pthread_detach函数pthread_detach函数用于将一个线程设置为分离状态,使其在退出时可以自动释放资源。

其原型如下:cint pthread_detach(pthread_t thread);参数说明:- thread:要设置为分离状态的线程ID二、线程退出函数1. pthread_exit函数pthread_exit函数用于退出当前线程,并返回一个值。

其原型如下:cvoid pthread_exit(void *retval);参数说明:- retval:线程的返回值2. pthread_cancel函数pthread_cancel函数用于取消一个线程的执行。

linux c entercriticalsection -回复

linux c entercriticalsection -回复

linux c entercriticalsection -回复在Linux C编程中,"进入临界区"是一个重要的概念。

临界区是指在多线程编程中,多个线程同时访问和修改共享资源的临界区域。

为了保证在临界区内数据的正确性和一致性,我们需要采取一些特殊的技术和机制来确保同一时间只有一个线程进入临界区。

本文将逐步回答关于Linux C编程中如何进入临界区的问题,并介绍一些常用的实现方法。

首先,为了理解临界区的概念和重要性,我们需要先了解共享资源和并发编程的基本概念。

在多线程编程中,多个线程可以同时访问和修改共享资源,比如全局变量、内存空间、文件等。

然而,当多个线程同时对同一个共享资源进行读写操作时,可能会导致数据的不一致和错误。

这就是临界区所要解决的问题。

那么如何进入临界区呢?在Linux C中,我们通常使用互斥锁(Mutex)来限制同时访问临界区的线程数量。

互斥锁是一种同步工具,它可以确保同一时间只有一个线程可以执行临界区内的代码。

在进入临界区之前,线程需要先获取互斥锁;在离开临界区后,线程需要释放互斥锁,以便其他线程能够获得锁并进入临界区。

下面是一步一步介绍如何使用互斥锁进入临界区的过程:第一步:包含头文件在使用互斥锁之前,我们需要包含头文件pthread.h,该文件中定义了互斥锁相关的函数和数据结构。

c#include <pthread.h>第二步:定义互斥锁变量在编写代码之前,我们需要定义一个互斥锁变量,以便后续使用。

cpthread_mutex_t mutex;第三步:初始化互斥锁在使用互斥锁之前,我们需要先对其进行初始化。

可以使用函数pthread_mutex_init来完成互斥锁的初始化。

cpthread_mutex_init(&mutex, NULL);第四步:进入临界区在需要进入临界区的地方,我们可以使用函数pthread_mutex_lock来尝试获取互斥锁。

Linux命令高级技巧使用xargs和parallel进行多线程命令执行

Linux命令高级技巧使用xargs和parallel进行多线程命令执行

Linux命令高级技巧使用xargs和parallel进行多线程命令执行在Linux系统中,命令行操作是一项非常重要的技能,掌握高级的命令行技巧对于提高工作效率和简化复杂任务是至关重要的。

本文将介绍如何使用xargs和parallel命令进行多线程命令执行的高级技巧。

1. 使用xargs进行多线程命令执行在Linux系统中,xargs命令可以用于将标准输入的内容转化为命令行参数,并将这些参数传递给指定命令进行执行。

这使得我们可以方便地并行执行多个命令,提高执行效率。

xargs的基本语法如下:```command | xargs [options] command ...```其中,第一个command产生一系列的参数,这些参数将作为输入传递给后面的command进行执行。

下面是一个示例,展示如何使用xargs命令同时查找多个文件中包含指定关键字的行数:```find /path/to/files -name "*.txt" | xargs grep -c "keyword"```在这个例子中,find命令用于查找指定路径下的所有扩展名为.txt的文件,并将文件列表传递给xargs命令。

xargs命令再将这些文件名作为参数传递给grep命令,执行关键字查找操作。

2. 使用parallel进行多线程命令执行与xargs类似,parallel也可以用于并行执行多个命令。

不同的是,parallel可以更精确地控制线程数量和命令执行顺序。

parallel的基本语法如下:```parallel [options] command < list-of-inputs```其中,command是需要并行执行的命令,list-of-inputs是作为命令参数的输入列表。

下面的示例展示了如何使用parallel命令在多个服务器上复制文件:```parallel -S server1,server2,server3 cp source_file {} ::: destination1 destination2 destination3```在这个例子中,-S选项指定了要在哪些服务器上执行命令。

linux下的CC++多进程多线程编程实例详解

linux下的CC++多进程多线程编程实例详解

linux下的CC++多进程多线程编程实例详解linux下的C\C++多进程多线程编程实例详解1、多进程编程#include <stdlib.h>#include <sys/types.h>#include <unistd.h>int main(){pid_t child_pid;/* 创建⼀个⼦进程 */child_pid = fork();if(child_pid == 0){printf("child pid\n");exit(0);}else{printf("father pid\n");sleep(60);}return 0;}2、多线程编程#include <stdio.h>#include <pthread.h>struct char_print_params{char character;int count;};void *char_print(void *parameters){struct char_print_params *p = (struct char_print_params *)parameters;int i;for(i = 0; i < p->count; i++){fputc(p->character,stderr);}return NULL;}int main(){pthread_t thread1_id;pthread_t thread2_id;struct char_print_params thread1_args;struct char_print_params thread2_args;thread1_args.character = 'x';thread1_args.count = 3000;pthread_create(&thread1_id, NULL, &char_print, &thread1_args);thread2_args.character = 'o';thread2_args.count = 2000;pthread_create(&thread2_id, NULL, &char_print, &thread2_args);pthread_join(thread1_id, NULL);pthread_join(thread2_id, NULL);return 0;}3、线程同步与互斥1)、互斥pthread_mutex_t mutex;pthread_mutex_init(&mutex, NULL);/*也可以⽤下⾯的⽅式初始化*/pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&mutex);/* 互斥 */thread_flag = value;pthread_mutex_unlock(&mutex);2)、条件变量int thread_flag = 0;pthread_mutex_t mutex;pthread_cond_t thread_flag_cv;\void init_flag(){pthread_mutex_init(&mutex, NULL);pthread_cond_init(&thread_flag_cv, NULL);thread_flag = 0;}void *thread_function(void *thread_flag){while(1){pthread_mutex_lock(&mutex);while(thread_flag != 0 ){pthread_cond_wait(&thread_flag_cv, &mutex);}pthread_mutex_unlock(&mutex);do_work();}return NULL;}void set_thread_flag(int flag_value){pthread_mutex_lock(&mutex);thread_flag = flag_value;pthread_cond_signal(&thread_flag_cv);pthread_mutex_unlock(&mutex);}感谢阅读,希望能帮助到⼤家,谢谢⼤家对本站的⽀持!。

linux和windows通用的多线程方法

linux和windows通用的多线程方法
多线程是一种在计算机程序中处理多个相似或相关的任务的技术。

无论是在Linux还是Windows中,多线程的实现都是类似的。

以下是一些通用的多线程方法:
1. 创建线程:使用线程库中提供的函数,例如在Linux中使用pthread_create(),在Windows中使用CreateThread()。

2. 同步线程:使用同步机制来保护共享资源,例如在Linux中使用pthread_mutex_lock()和pthread_mutex_unlock(),在Windows 中使用CriticalSection。

3. 线程间通信:使用消息传递或共享内存等机制来实现线程间通信。

在Linux中,可以使用管道、共享内存和信号量等。

在Windows 中,可以使用命名管道和邮槽等。

4. 线程池:创建一个线程池来管理多个线程,这样可以避免频繁地创建和销毁线程,提高效率。

5. 轮询:使用循环不断地检查线程是否完成任务,从而避免阻塞主线程。

总的来说,多线程在Linux和Windows中的实现都是类似的,只要掌握了基本的多线程概念和方法,就可以在两个操作系统中进行开发。

第6章 linux进程控制开发及多线程编程


进程的状态
进程是程序的执行过程,根据它的生命周期可以划分成3种 状态。 执行态:该进程正在运行,即进程正在占用CPU。 就绪态:进程已经具备执行的一切条件,正在等待分配 CPU的处理时间片。 等待态:进程不能使用CPU,若等待事件发生(等待的 资源分配到)则可将其唤醒。
Linux下进程地址空间(1)
互斥锁线程控制 (1)
在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态 的线程能够对共享资源进行操作。若其他线程希望上锁一个 已经被上锁的互斥锁,则该线程就会挂起,直到上锁的线程 释放掉互斥锁为止。
互斥锁机制主要包括下面的基本函数。 互斥锁初始化: pthread_mutex_init() 互斥锁上锁: pthread_mutex_lock() 互斥锁判断上锁:pthread_mutex_trylock() 互斥锁解锁: pthread_mutex_unlock() 消除互斥锁: pthread_mutex_destroy()
示例
阅读并执行示例7-2-4 开始
教材P216-P217
fork()
程序功能: (1)使用fork创建一个子进程, 然后让其子进程暂停5s(sleep函 数)。 (2)父进程使用waitpid,参数 WNOHANG使进程不会阻塞; (3)若子进程退出,则waitpid返 回子进程号,若没有则waitpid返 回0,并且父进程每隔一秒循环判 断。
因此,可以通过返回值来判定该进程是父进程还是子进程。
fork示例
1.Fork返回两个值返回到哪里??
int main(void)
{

pid_t result;
2.怎样区分是父、子进程??

result = fork();

嵌入式Linux多线程编程实验

实验二、嵌入式Linux多线程编程实验一、实验目的1. 熟悉线程的定义、创建及应用方法,掌握编译源代码时引入线程库的方法。

2. 掌握如何利用信号量完成线程间的同步与互斥。

3. 熟悉Makefile工作原理,掌握编写Makefile的编写方法。

二、实验基本要求1. 掌握熟悉线程的定义及操作方法。

2. 利用信号量的PV操作完成完成以下单个生产者和单个消费者模型的代码。

3. 编写在Ubuntu中编译执行的makefile文件,然后在Ubuntu中执行。

4. 编写在实验箱中编译执行的makefile文件,然后在实验箱中执行。

注意Makefile编写规范缩进应使用制表键即Tab键。

三、实验原理1.Linux线程的定义线程(thread)是在共享内存空间中并发的多道执行路径,它们共享一个进程的资源,如文件描述和信号处理。

在两个普通进程(非线程)间进行切换时,内核准备从一个进程的上下文切换到另一个进程的上下文要花费很大的开销。

这里上下文切换的主要任务是保存老进程CPU状态并加载新进程的保存状态,用新进程的内存映像替换进程的内存映像。

线程允许你的进程在几个正在运行的任务之间进行切换,而不必执行前面提到的完整的上下文。

另外本文介绍的线程是针对POSIX线程,也就是pthread。

也因为Linux对它的支持最好。

相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。

在串行程序基础上引入线程和进程是为了提高程序的并发度,从而提高程序运行效率和响应时间。

也可以将线程和轻量级进程(LWP)视为等同的,但其实在不同的系统/实现中有不同的解释,LWP更恰当的解释为一个虚拟CPU或内核的线程。

它可以帮助用户态线程实现一些特殊的功能。

Pthread是一种标准化模型,它用来把一个程序分成一组能够同时执行的任务。

2. 什么场合会使用Pthread即线程(1) 在返回前阻塞的I/O任务能够使用一个线程处理I/O,同时继续执行其他处理任务。

Linux下c语言多线程编程

Linux下c语⾔多线程编程引⾔ 线程(thread)技术早在60年代就被提出,但真正应⽤多线程到中去,是在80年代中期,solaris是这⽅⾯的佼佼者。

传统的Unix也⽀持线程的概念,但是在⼀个进程(process)中只允许有⼀个线程,这样多线程就意味着多进程。

现在,多 为什么有了进程的概念后,还要再引⼊线程呢?使⽤多线程到底有哪些好处?什么的系统应该选⽤多线程?我们⾸先必须回答这些问题。

使⽤多线程的理由之⼀是和进程相⽐,它是⼀种⾮常"节俭"的多任务操作⽅式。

我们知道,在Linux系统下,启动⼀个新的进程必须分配给它独⽴的地址空间,建⽴众多的数据表来维护它的代码段、堆栈段和数据段,这是⼀种"昂贵"的多任务⼯作⽅式。

⽽运⾏于⼀个进程中的多个线程,它们彼此之间使⽤相同的地址空间,共享⼤部分数据,启动⼀个线程所花费的空间远远⼩于启动⼀个进程所花费的空间,⽽且,线程间彼此切换所需的时间也远远⼩于进程间切换所需要的时间。

使⽤多线程的理由之⼆是线程间⽅便的机制。

对不同进程来说,它们具有独⽴的数据空间,要进⾏数据的传递只能通过通信的⽅式进⾏,这种⽅式不仅费时,⽽且很不⽅便。

线程则不然,由于同⼀进程下的线程之间共享数据空间,所以⼀个线程的数据可以直接为其它线程所⽤,这不仅快捷,⽽且⽅便。

当然,数据的共享也带来其他⼀些问题,有的变量不能同时被两个线程所修改,有的⼦程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地⽅。

除了以上所说的优点外,不和进程⽐较,多线程程序作为⼀种多任务、并发的⼯作⽅式,当然有以下的优点: 1) 提⾼应⽤程序响应。

这对图形界⾯的程序尤其有意义,当⼀个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应、、菜单的操作,⽽使⽤多线程技术,将耗时长的操作(time consuming)置于⼀个新的线程,可以避免这种尴尬的情况。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档