Linux的POSIX线程

简述

POSIX线程(Pthreads)是一种标准的多线程API,它提供了一组函数和数据类型,使得程序员能够使用多个线程来并发执行任务。POSIX线程支持在类Unix操作系统上运行,并且是跨平台的。

方法

下面是一些常用的POSIX线程函数和数据类型:

pthread_t

表示线程的数据类型,它是一个不透明的结构体类型,通常实现为指向线程控制块(Thread Control Block,TCB)的指针。定义在 <pthread.h> 头文件中

pthread_create()

该函数用于创建一个新线程。它的原型如下:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

参数说明:

  • thread:指向新线程的 ID,如果创建线程成功,它会被填充为新线程的 ID
  • attr: 用于设置新线程的属性,如果传入 NULL,则使用默认的线程属性。
  • start_routine:是新线程的入口函数,它是一个函数指针,指向新线程要执行的函数
  • arg:是传递给 start_routine 函数的参数

在调用 pthread_create() 函数时,会创建一个新线程,并且新线程会执行 start_routine 函数。如果 start_routine 函数执行成功并正常退出,新线程会自动退出,并且可以通过调用 pthread_join() 函数来获取新线程的退出状态。如果 start_routine 函数发生错误或者异常退出

pthread_join()

用于等待一个线程的结束并获取其退出状态的函数。它的原型如下:

int pthread_join(pthread_t thread, void **retval);

参数说明:

  • thread:要等待的线程ID
  • retval:线程的返回值,可以为NULL

pthread_exit()

该函数用于在线程中终止一个线程。它可以返回一个值,或者不返回任何值。

void pthread_exit(void *value_ptr);

参数说明:

  • value_ptr: 作为线程的退出状态,通知其他线程该线程的执行情况。

pthread_mutex_t

该数据类型表示互斥锁。互斥锁是一种同步机制,用于控制对共享资源的访问。它的原型如下:

typedef struct {
    
    
    // ...
} pthread_mutex_t;

pthread_mutex_init()

该函数用于动态初始化互斥锁。它的原型如下:

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

PTHREAD_MUTEX_INITIALIZER 用于静态定义的互斥锁,也就是在编译时已经确定的互斥锁。

eg:

static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;

参数说明:

  • mutex:要初始化的互斥锁。
  • attr:互斥锁的属性,可以为NULL

pthread_mutex_lock()

该函数用于获取互斥锁。如果互斥锁已被其他线程占用,则当前线程会阻塞。它的原型如下:

int pthread_mutex_lock(pthread_mutex_t *mutex);

参数说明:

  • mutex:要获取的互斥锁。

pthread_mutex_unlock()

该函数用于释放互斥锁。它的原型如下:

int pthread_mutex_unlock(pthread_mutex_t *mutex);

参数说明:

  • mutex:要释放的互斥锁。

pthread_mutex_destroy()

用于销毁互斥锁的函数,它的原型如下:

int pthread_mutex_destroy(pthread_mutex_t *mutex);

参数说明:

  • mutex:指向互斥锁的指针。

pthread_cond_t

该数据类型,用于实现线程间的条件变量同步(即用于在不同的线程之间传递信号)。它通常与 pthread_cond_wait()pthread_cond_signal()pthread_cond_broadcast() 等函数一起使用。它的原型如下:

typedef struct {
    
    
    // ...
} pthread_cond_t;

可以使用 pthread_cond_init() 或者 PTHREAD_COND_INITIALIZER 来初始化条件变量。

pthread_cond_init()

该函数用于初始化条件变量。它的原型如下:

int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);

参数说明:

  • cond:要初始化的条件变量。
  • attr:条件变量的属性,可以为NULL。

pthread_cond_wait()

该函数的作用是在等待条件变量的值变为非零时,使线程阻塞并等待条件变量被其他线程发出的信号唤醒。
当线程调用pthread_cond_wait()时,它将被阻塞,直到另一个线程调用pthread_cond_signal()pthread_cond_broadcast()来通知它条件已经满足。它的原型如下:

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

参数说明:

  • cond:条件变量指针。
  • mutex:互斥锁指针。调用该函数前需要获取锁,函数返回前会自动释放锁。

pthread_cond_signal()

用于向等待某个条件变量的线程广播一个信号,唤醒一个等待在条件变量上的线程,如果有多个线程等待,则只会唤醒其中的一个。如果没有等待的线程,则该操作不会有任何效果。它通常与 pthread_cond_wait() 配合使用,用于线程间的条件变量同步。

int pthread_cond_signal(pthread_cond_t *cond);

参数说明:

  • cond:条件变量指针。

pthread_cond_broadcast()

用于向等待某个条件变量的线程广播一个信号,以唤醒所有等待该条件变量的线程。它通常与 pthread_cond_wait() 配合使用,用于线程间的条件变量同步。它的原型如下:

int pthread_cond_broadcast(pthread_cond_t *cond);

参数说明:

  • cond:条件变量指针。

pthread_cond_destroy()

用于销毁条件变量的函数。它的原型如下:

int pthread_cond_destroy(pthread_cond_t *cond);

sem_t

它是一个不透明的数据结构,定义在 <semaphore.h> 头文件中,用于表示一个信号量。sem_t 变量通常是由 sem_init() 函数创建,并在使用完毕后由 sem_destroy() 函数销毁

sem_init()

用于初始化一个信号量。它的原型如下:

int sem_init(sem_t *sem, int pshared, unsigned int value);

参数说明:

  • sem:指向需要初始化的信号量变量的指针。
  • pshared:指定信号量的类型,取值可以是 01。当 pshared 的值为 0 时,表示信号量只能在当前进程的多个线程之间共享;当 pshared 的值为 1 时,表示信号量可在多个进程之间共享。
  • value:指定信号量的初始值。信号量的值必须是一个非负整数,表示资源的可用数量。通常情况下,初始值为 1 表示只有一个资源可用,初始值为 0 表示没有资源可用。

sem_wait()

用于获取(等待)一个信号量,即对信号量进行 P 操作(等待操作:当一个线程或进程需要占用资源时,会试图执行 P 操作来获取信号量。如果信号量的值大于 0,则减少信号量的值并继续执行;否则,线程或进程会阻塞等待信号量的值大于 0),

int sem_wait(sem_t *sem);

参数说明:

  • sem:指向信号量变量的指针。

sem_post()

用于释放(发送)一个信号量,即对信号量进行 V 操作(释放操作:当一个线程或进程不再需要占用资源时,会执行 V 操作来释放信号量。该操作将信号量的值增加 1,以通知其他线程或进程可以继续执行了)。

int sem_post(sem_t *sem);

参数说明:

  • sem:指向信号量变量的指针。

sem_destroy()

用于销毁一个已经初始化的信号量。它的原型如下:

int sem_destroy(sem_t *sem);

参数说明:

  • sem:指向信号量变量的指针。

pthread_key_t

用于创建线程私有数据(Thread-Specific Data,简称 TSD)。线程私有数据是指每个线程都拥有独立的数据空间,线程之间的数据不会相互影响。在多线程程序中,有时需要为每个线程分配独立的数据空间,以便线程可以独立地访问和修改数据。

pthread_key_create()

创建一个线程私有数据的键。

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*))

参数说明:

  • key: 是一个指向 pthread_key_t 类型的指针,用于存储创建的线程私有数据的键
  • destructor : 是一个回调函数,用于在线程退出时自动释放线程私有数据。如果不需要自动释放线程私有数据,可以将 destructor 参数设置为 NULL
  • 函数执行成功时返回 0,否则返回一个非 0 的错误码。

pthread_setspecific()

为当前线程设置线程私有数据

int pthread_setspecific(pthread_key_t key, const void *value)

参数说明:

  • key:是一个线程私有数据的键
  • value:是一个指向数据的指针,用于设置线程私有数据的值
  • 函数执行成功时返回 0,否则返回一个非 0 的错误码

pthread_getspecific()

获取当前线程的线程私有数据

void *pthread_getspecific(pthread_key_t key)

参数说明:

  • key:是一个线程私有数据的键,用于获取线程私有数据的值。
  • 函数返回一个指向线程私有数据的指针,如果线程没有设置该线程私有数据,返回 NULL

pthread_key_delete()

删除一个线程私有数据的键

int pthread_key_delete(pthread_key_t key)

参数说明:

  • key:一个线程私有数据的键,用于删除该键以及对应的线程私有数据。
  • 如果线程私有数据的键成功删除,函数返回 0,否则返回一个非 0 的错误码。

pthread_once_t

POSIX 线程库中的一个类型,用于表示 pthread_once 函数中的控制变量,用于保证一个函数只会被执行一次。实际上是一个 volatile int 类型,也就是说它是一个 volatileint 类型变量,因此可以保证该变量的值在多线程程序中的读写操作不会被优化或者重排序。

它的原型是:

typedef volatile int pthread_once_t;

pthread_once_t 变量的初始化应该使用 PTHREAD_ONCE_INIT 宏,该宏定义在 pthread.h 头文件中,其定义如下:

#define PTHREAD_ONCE_INIT   0

需要注意的是,pthread_once_t 变量必须是静态变量或者全局变量,否则可能会出现竞态条件问题。此外,由于 pthread_once_t 变量的读写操作需要保证原子性和可见性,因此在使用该变量时需要遵守内存模型和同步机制的规定。

pthread_key_delete()

用于保证一个函数只会被执行一次。在多线程编程中,当有多个线程需要执行同一个初始化函数时,使用 pthread_once 函数可以保证该函数只会被执行一次,从而避免了并发访问导致的竞态条件问题。
它的原型如下:

int pthread_once(pthread_once_t* once_control, void (*init_func)(void));

参数说明:

  • once_control:一个 pthread_once_t 类型的变量的指针
  • init_func: 一个函数指针,表示需要保证只被执行一次的初始化函数

例子

创建线程

#include <pthread.h>
#include <stdio.h>

void *thread_function(void *arg) {
    
    
  printf("Hello from thread!\n");
  pthread_exit(NULL);
}

int main() {
    
    
  pthread_t my_thread;
  int ret = pthread_create(&my_thread, NULL, thread_function, NULL);
  if (ret != 0) {
    
    
    printf("Failed to create thread.\n");
    return -1;
  }
  printf("Thread created.\n");
  pthread_join(my_thread, NULL);
  printf("Thread joined.\n");
  return 0;
}
/*
执行结果:
Thread created.
Hello from thread!
Thread joined.
*/

给线程传递参数

#include <pthread.h>
#include <stdio.h>

void *thread_function(void *arg) {
    
    
  int *num_ptr = (int *)arg;
  printf("Hello from thread! The number is %d.\n", *num_ptr);
  pthread_exit(NULL);
}

int main() {
    
    
  pthread_t my_thread;
  int num = 42;
  int ret = pthread_create(&my_thread, NULL, thread_function, &num);
  if (ret != 0) {
    
    
    printf("Failed to create thread.\n");
    return -1;
  }
  printf("Thread created.\n");
  pthread_join(my_thread, NULL);
  printf("Thread joined.\n");
  return 0;
}
/*
执行结果:
Thread created.
Hello from thread! The number is 42.
Thread joined.
*/

线程同步(使用互斥锁)

#include <pthread.h>
#include <stdio.h>

int counter = 0;
pthread_mutex_t counter_mutex;

void *thread_function(void *arg) {
    
    
  int i; 
  for (i = 0; i < 1000000; i++) {
    
    
    pthread_mutex_lock(&counter_mutex);
    counter++;
    pthread_mutex_unlock(&counter_mutex);
  }
  pthread_exit(NULL);
}

int main() {
    
    
  pthread_t threads[4];
  pthread_mutex_init(&counter_mutex, NULL);
  int i; 
  for (i = 0; i < 4; i++) {
    
    
    pthread_create(&threads[i], NULL, thread_function, NULL);
  }
  for (i = 0; i < 4; i++) {
    
    
    pthread_join(threads[i], NULL);
  }
  pthread_mutex_destroy(&counter_mutex);
  printf("Counter value: %d\n", counter);
  return 0;
}
/*
执行结果:
Counter value: 4000000
*/

线程同步(使用条件变量)

#include <pthread.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>

bool flag = false;
pthread_mutex_t flag_mutex;
pthread_cond_t flag_cond;

void *thread_function(void *arg) {
    
    
  printf("Thread waiting for flag to be set...\n");
  pthread_mutex_lock(&flag_mutex);
  while (!flag) {
    
    
	printf("go thread here start...\n");
    pthread_cond_wait(&flag_cond, &flag_mutex);
	printf("go thread here end...\n");
  }
  pthread_mutex_unlock(&flag_mutex);
  printf("Flag has been set, thread exiting.\n");
  pthread_exit(NULL);
}

int main() {
    
    
  pthread_t my_thread;
  pthread_mutex_init(&flag_mutex, NULL);
  pthread_cond_init(&flag_cond, NULL);
  pthread_create(&my_thread, NULL, thread_function, NULL);
  sleep(1);
  printf("Setting flag to true...\n");
  pthread_mutex_lock(&flag_mutex);
  flag = true;
  printf("go main here start...\n");
  pthread_cond_signal(&flag_cond);
  printf("go main here mid...\n");
  pthread_mutex_unlock(&flag_mutex);
  printf("go main here end...\n");
  pthread_join(my_thread, NULL);
  pthread_mutex_destroy(&flag_mutex);
  pthread_cond_destroy(&flag_cond);
  return 0;
}
/*
执行结果:
Thread waiting for flag to be set...
go thread here start...
Setting flag to true...
go main here start...
go main here mid...
go main here end...
go thread here end...
Flag has been set, thread exiting.
*/

线程同步(使用信号量)

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

#define BUFFER_SIZE 10

int buffer[BUFFER_SIZE];
int buffer_count = 0;

sem_t mutex; // 互斥信号量,保证 buffer_count 的原子性
sem_t empty; // 空信号量,表示 buffer 中空槽数量
sem_t full; // 满信号量,表示 buffer 中满槽数量

void* producer(void* arg) {
    
    
    int i, data;
    for (i = 0; i < 20; ++i) {
    
    
        data = rand() % 100;
        sem_wait(&empty); // 等待空槽
        sem_wait(&mutex); // 保证 buffer_count 的原子性
        buffer[buffer_count++] = data;
        printf("Produced: %d\n", data);
        sem_post(&mutex);
        sem_post(&full); // 释放一个满槽
        usleep(rand() % 100000); // 产生一定的延迟,模拟生产过程
    }
    return NULL;
}

void* consumer(void* arg) {
    
    
    int i, data;
    for (i = 0; i < 20; ++i) {
    
    
        sem_wait(&full); // 等待满槽
        sem_wait(&mutex); // 保证 buffer_count 的原子性
        data = buffer[--buffer_count];
        printf("Consumed: %d\n", data);
        sem_post(&mutex);
        sem_post(&empty); // 释放一个空槽
        usleep(rand() % 100000); // 消费过程中也产生一定的延迟
    }
    return NULL;
}

int main() {
    
    
    pthread_t producer_tid, consumer_tid;
    sem_init(&mutex, 0, 1); // 初始化互斥信号量为 1
    sem_init(&empty, 0, BUFFER_SIZE); // 初始化空信号量为 BUFFER_SIZE
    sem_init(&full, 0, 0); // 初始化满信号量为 0
    pthread_create(&producer_tid, NULL, producer, NULL);
    pthread_create(&consumer_tid, NULL, consumer, NULL);
    pthread_join(producer_tid, NULL);
    pthread_join(consumer_tid, NULL);
    sem_destroy(&mutex);
    sem_destroy(&empty);
    sem_destroy(&full);
    return 0;
}
/*
代码可能的执行结果:(里面用到rand(),回来的数是随机的)
Produced: 83
Consumed: 83
Produced: 15
Produced: 35
Consumed: 35
Consumed: 15
Produced: 21
Produced: 27
Consumed: 27
Consumed: 21
Produced: 26
Consumed: 26
Produced: 72
Consumed: 72
Produced: 68
Produced: 29
Consumed: 29
Consumed: 68
Produced: 23
Consumed: 23
Produced: 29
Consumed: 29
Produced: 58
Consumed: 58
Produced: 93
Produced: 11
Consumed: 11
Produced: 73
Consumed: 73
Produced: 84
Consumed: 84
Consumed: 93
Produced: 15
Produced: 13
Produced: 91
Consumed: 91
Consumed: 13
Produced: 62
Consumed: 62
Consumed: 15
*/

猜你喜欢

转载自blog.csdn.net/weixin_45767368/article/details/129279171
今日推荐