8种机械键盘轴体对比
本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?
若函数可同时供多个线程安全调用,则称之为线程安全函数。反之,如果不是线程安全的,就不能并发调用。
一次性初始化
#include
int pthread_once(pthread_once_t *once_control, void (*init)(void));
/* 成功返回0,失败返回正的errno值 */
利用参数once_control的状态,函数pthread_once可以确保无论有多少线程对pthread_once调用了多少次,也只会执行一次由init指向的调用者定义的函数。
pthread_once_t once_var = PTHREAD_ONCE_INIT;
once_control是指向如上once_var静态变量的指针。
线程特有数据
实现函数线程安全最为有效的方式是使其可重入,应以这种方式实现所有新的函数库。不过,对于已有的不可重入函数库来说,采用这种方法通常要修改函数接口,这意味着,需要修改所有使用此类函数库的应用程序。
使用线程特有数据技术,可以无需修改函数接口而实现已有函数的线程安全。较之于可重入函数,采用线程特有数据的函数效率可能要略低一些,不过对于使用了这些调用的程序而言,则省去了修改程序之劳。
线程特有数据使函数得以为每个调用线程分别维护一份变量的副本。线程特有数据是长期存在的,在同一线程对相同函数的历次调用间,每个现成的变量会持续存在,函数可以向每个调用线程返回各自的结果缓冲区(如果需要的话)。
库函数视角下的线程特有数据该函数必须为每个调用者线程分配单独的存储,且只需在线程第一次调用此函数时分配一次即可。
在同一线程对此函数的后续所有调用中,该函数都需要获取初次调用时线程分配的存储块地址。由于函数调用结束会释放自动变量,且静态变量在进程中只有一个实例,因此无法将指针存放于自动变量或静态变量中。Pthread API提供了函数来处理这一情况。
不同(无相互依赖关系)函数各自可能都需要使用线程特有数据。每个函数都需要方法来标识其自身的线程特有数据(键),以便与其他函数所使用的线程特有数据有所区分。
当线程退出时,函数无法控制将要发生的情况。这时,线程可能会执行该函数之外的代码。不过,一定存在某些机制,在线程退出时自动释放为该线程所分配的存储。
线程特有数据API概述函数创建一个键(key),用以将不同函数使用的线程特有数据项区分来开。调用函数pthread_key_create可创建此键,且只需要在该线程首次调用该函数时创建一次,函数pthread_once的使用正是出于这一目的。键在创建时并未分配任何线程特有数据块。
调用pthread_key_create还有另一目的,即允许调用者指定一个自定义解构函数。用于释放为该键所分配的各个存储块。当使用线程特有数据的线程终止时,Pthreads API会自动调用此解构函数,同时将该线程的数据块指针作为参数传入。
函数会为每个调用者线程创建线程特有数据块。这一分配通过调用malloc(或类似函数)完成,每个线程只分配一次,且只会在线程初次调用此函数时分配。
为了保存上一步所分配的内存块地址,函数会使用两个Pthreads函数:pthread_setspecific和pthread_getspecific。调用函数pthread_setspecific实际上是Pthreads实现发起这样的请求:保存该指针,并记录其与特定键(该函数的键)以及特定线程(调用者线程)的关联性。调用pthread_getspecific所执行的是互补操作:返回之前所保存的,与给定键以及调用线程相关联的指针,若无,返回NULL。
线程特有数据API详述
函数pthread_key_create函数为线程特有数据创建一个新键,并通过key指向的缓冲区返回给调用者。
#include
int pthread_key_create(pthread_key_t *key, void(*destructor)(void *));
/* 成功返回0,失败返回正的errno值 */
因为进程中的所有线程都可使用返回的键,所以参数key应指向一个全局变量。
只要destructor不为NULL,Pthreads API会自动调用该函数,并将key的关联值作为参数传入解构函数。传入的值通常是与该键关联,且指向线程特有数据块的指针。
函数pthread_setspecific要求Pthreads API将value的副本存储于一数据结构中,并将value与调用线程以及key相关联。
函数pthread_getspecific函数执行的操作与之相反,返回之前与本线程及给定key相关的值。
#include
int pthread_setspecific(pthread_key_t ket, const void *value);
/* 成功返回0,失败返回正的errno值 */
void *pthread_getspecific(pthread_key_t key);
/* 返回线程特有数据块的指针,或者NULL */
函数pthread_setspecific的参数通常是一指针,指向由调用者分配的一块内存。当线程终止时,会将该指针作为参数传递给与key对应的解构函数。
使用线程特有数据API包括Linux在内的众多UNIX实现中,由标准C语言函数库提供的strerror函数都是线程安全的。
非线程安全版strerror
该函数利用了由glibc定义的一对全局变量,_sys_errlist是一个指针数组,其每个元素指向一个与errno相匹配的字符串;_sys_nerr表示_sys_errlist中的元素个数。
#define _GNU_SOURCE
#include
#include
#define MAX_ERROR_LEN 256
static char buf[MAX_ERROR_LEN];
char *strerror(int err)
{
if (err < 0 || err >= _sys_nerr || _sys_errlist[err] == NULL) {
snprintf(buf, MAX_ERROR_LEN, "Unknown error %d", err);
} else {
strncpy(buf, _sys_errlist[err], MAX_ERROR_LEN - 1);
buf[MAX_ERROR_LEN - 1] = '