多线程编程(Linux系统下)

目录

多线程编程(Linux系统下)

一、线程机制

1、创建线程

函数原型:

参数说明:

返回值:

示例代码:

2、终止线程

函数原型:

参数说明:

示例代码:

3、等待一个线程结束,并获取该线程的返回值

函数原型:

参数说明:

返回值:

示例代码:

4、向指定线程发送取消请求

函数原型:

参数说明:

返回值:

示例代码:

二、线程之间的同步与互斥

互斥锁

1、互斥锁的初始化

函数原型:

参数说明:

返回值:

互斥锁属性:

示例代码:

2、上锁

函数原型:

参数说明:

返回值:

示例代码:

3、尝试对互斥锁进行加锁操作,可用于判断是否加锁

函数原型

参数说明:

返回值:

示例代码:

4、解锁

函数原型:

参数说明:

返回值:

示例代码:

5、销毁锁

函数原型:

参数说明:

返回值:

示例代码:

条件变量

1、初始化一个条件变量

函数原型:

参数:

返回值:

注意事项:

示例代码

2、销毁一个条件变量

函数原型:

参数:

返回值:

注意事项:

示例代码:

3、唤醒所有正在等待指定条件变量的线程

函数原型:

参数:

返回值:

注意事项:

示例代码:

输出示例:

使用场景:

4、唤醒一个正在等待指定条件变量的线程

函数原型:

参数:

返回值:

注意事项:

互斥锁:

线程状态:

性能考虑:

线程安全:

示例代码:

输出示例

5、线程等待某个条件变量

函数原型:

参数:

功能:

返回值:

注意事项:

互斥锁的持有:

虚假唤醒:

线程安全:

性能考虑:

示例代码:

输出示例:

信号量

1、初始化信号量

函数原型:

参数说明:

返回值:

注意事项:

示例代码:

2、P操作

函数原型1:

返回值:

示例代码:

函数原型:

功能描述:

返回值:

示例代码:

3、V操作

函数原型:

返回值:

示例代码:

4、获取信号量的值

函数原型:

返回值:

示例代码:

5、删除信号量

函数原型:

返回值:

示例代码:

三、线程属性

1、初始化线程属性对象

函数原型:

返回值:

示例代码:

2、设置线程属性对象的分离状态属性

函数原型

参数:

返回值:

示例代码:

3、获取线程属性对象中的调度参数属性

函数原型:

参数:

返回值:

错误码:

示例代码:

函数原型:

功能描述:

参数:

返回值:

错误码:

示例代码


多线程编程(Linux系统下)

一、线程机制

1、创建线程

在 Linux 系统下,pthread_create 是一个用于创建线程的函数,属于 POSIX 线程(pthread)库。

函数原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
参数说明:
  • thread:线程标识符,用于唯一标识新创建的线程。如果不需要线程标识符,可以传入 NULL

  • attr:线程属性,用于设置线程的属性,如栈大小、栈地址、线程分离状态等。如果使用默认属性,可以传入 NULL

  • start_routine:线程函数的入口点,线程开始执行时将调用此函数。该函数的返回值类型为 void *,参数类型为 void *

  • arg:传递给线程函数的参数。如果不需要传递参数,可以传入 NULL

返回值:
  • 成功时返回 0

  • 失败时返回错误码(非零值),例如:

    • EAGAIN:系统资源不足,无法创建新线程。

    • EINVAL:输入参数无效。

    • EPERM:权限不足。

示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
​
// 线程函数
void *thread_function(void *arg) {
    int num = *(int *)arg;
    printf("Thread is running with argument: %d\n", num);
    return NULL;
}
​
int main() {
    pthread_t thread;
    int arg = 42;
​
    // 创建线程
    if (pthread_create(&thread, NULL, thread_function, &arg) != 0) {
        perror("Failed to create thread");
        return EXIT_FAILURE;
    }
​
    // 等待线程结束
    if (pthread_join(thread, NULL) != 0) {
        perror("Failed to join thread");
        return EXIT_FAILURE;
    }
​
    printf("Thread has finished execution.\n");
    return EXIT_SUCCESS;
}

2、终止线程

在 Linux 系统中,pthread_exit 是 POSIX 线程库(pthread)提供的一个函数,用于终止当前线程的执行。

函数原型:
void pthread_exit(void *retval);
  • pthread_exit 会导致调用它的线程终止执行。

  • 当线程终止时,它会释放与线程相关的资源(如线程局部存储、栈空间等),但不会释放全局资源。

  • 如果线程是可加入的(joinable),其他线程可以通过 pthread_join 获取线程的返回值。

  • 如果线程是分离的(detached),线程终止后,其资源会立即被释放,线程的返回值不会被保留。

参数说明:
  • retval:线程的返回值。当其他线程通过 pthread_join 等待该线程结束时,retval 将被传递给 pthread_join 的第二个参数(void **value_ptr)。如果线程没有被其他线程等待,retval 的值不会被使用。

示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
​
// 线程函数
void *thread_function(void *arg) {
    printf("Thread is running.\n");
    // 终止线程并返回值
    pthread_exit((void *)42);
}
​
int main() {
    pthread_t thread;
    void *thread_return;
​
    // 创建线程
    if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
        perror("Failed to create thread");
        return EXIT_FAILURE;
    }
​
    // 等待线程结束并获取返回值
    if (pthread_join(thread, &thread_return) != 0) {
        perror("Failed to join thread");
        return EXIT_FAILURE;
    }
​
    printf("Thread has finished execution. Return value: %ld\n", (long)thread_return);
    return EXIT_SUCCESS;
}

输出示例

Thread is running.
Thread has finished execution. Return value: 42

3、等待一个线程结束,并获取该线程的返回值

在 Linux 系统中,pthread_join 是 POSIX 线程库(pthread)提供的一个函数,用于等待一个线程结束,并获取该线程的返回值。它是线程同步机制的一种,确保线程安全地结束并释放资源。

函数原型:
int pthread_join(pthread_t thread, void **value_ptr);
  • pthread_join 会阻塞调用它的线程,直到指定的线程结束。

  • 如果指定的线程已经结束,pthread_join 会立即返回,并将线程的返回值存储到 value_ptr 指向的地址。

  • 如果线程是分离的(detached),调用 pthread_join 会导致错误,因为分离的线程在终止时会立即释放资源,无法被等待。

参数说明:
  • thread:要等待的线程的标识符。这个标识符是在调用 pthread_create 时生成的。

  • value_ptr:一个指针,用于存储线程函数的返回值。如果不需要获取返回值,可以传入 NULL

返回值:
  • 成功时返回 0

  • 失败时返回错误码(非零值),常见的错误码包括:

    • EINVALthread 参数无效。

    • ESRCH:指定的线程不存在。

    • EINVALvalue_ptr 不是有效的指针。

    • EDEADLK:尝试等待一个已经终止的线程,或者尝试等待自己。

示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
​
// 线程函数
void *thread_function(void *arg) {
    int num = *(int *)arg;
    printf("Thread is running with argument: %d\n", num);
    // 线程返回值
    return (void *)(num * 2);
}
​
int main() {
    pthread_t thread;
    int arg = 42;
    void *thread_return;
​
    // 创建线程
    if (pthread_create(&thread, NULL, thread_function, &arg) != 0) {
        perror("Failed to create thread");
        return EXIT_FAILURE;
    }
​
    // 等待线程结束并获取返回值
    if (pthread_join(thread, &thread_return) != 0) {
        perror("Failed to join thread");
        return EXIT_FAILURE;
    }
​
    printf("Thread has finished execution. Return value: %ld\n", (long)thread_return);
    return EXIT_SUCCESS;
}

输出示例

Thread is running with argument: 42
Thread has finished execution. Return value: 84

4、向指定线程发送取消请求

在 Linux 系统中,pthread_cancel 是一个用于向指定线程发送取消请求的函数。

函数原型:
int pthread_cancel(pthread_t thread);
  • pthread_cancel 向目标线程发送取消请求,但目标线程是否以及何时响应该请求取决于目标线程的可取消状态和类型。

  • 目标线程的可取消状态可以通过 pthread_setcancelstate 设置,分为:

    • PTHREAD_CANCEL_ENABLE(默认):线程可以被取消。

    • PTHREAD_CANCEL_DISABLE:线程不能被取消。

  • 目标线程的可取消类型可以通过 pthread_setcanceltype 设置,分为:

    • PTHREAD_CANCEL_DEFERRED(默认):取消请求会被延迟,直到线程调用一个取消点(如 sleeppthread_join 等)。

    • PTHREAD_CANCEL_ASYNCHRONOUS:线程可以随时被取消。

  • 当取消请求被处理时,目标线程会执行以下操作:

    1. 调用取消清理处理器(按相反顺序)。

    2. 调用线程特定数据的析构函数。

    3. 终止线程,等同于调用 pthread_exit(PTHREAD_CANCELED)

参数说明:
  • thread:目标线程的标识符,该标识符是在调用 pthread_create 时生成的。

返回值:
  • 成功时返回 0

  • 失败时返回错误码,常见的错误码包括:

    • ESRCH:指定的线程不存在。

示例代码:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void *thread_function(void *arg) {
    printf("Thread started. Sleeping for 10 seconds...\n");
    sleep(10);  // 取消点
    printf("Thread finished.\n");
    return NULL;
}

int main() {
    pthread_t thread;
    void *status;

    if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
        perror("Failed to create thread");
        return 1;
    }

    sleep(1);  // 给线程一些时间启动

    if (pthread_cancel(thread) != 0) {
        perror("Failed to cancel thread");
        return 1;
    }

    if (pthread_join(thread, &status) != 0) {
        perror("Failed to join thread");
        return 1;
    }

    if (status == PTHREAD_CANCELED) {
        printf("Thread was canceled.\n");
    } else {
        printf("Thread was not canceled.\n");
    }

    return 0;
}

输出示例

Thread started. Sleeping for 10 seconds...
Thread was canceled.

二、线程之间的同步与互斥

互斥锁

1、互斥锁的初始化

在 Linux 系统中,pthread_mutex_init 是 POSIX 线程库(pthread)提供的一个函数,用于初始化互斥锁(mutex)。互斥锁是一种同步机制,用于保护共享资源,防止多个线程同时访问。

函数原型:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
参数说明:
  • mutex:指向互斥锁的指针。需要初始化的互斥锁对象。

  • attr:互斥锁的属性。如果使用默认属性,可以传入 NULL

返回值:
  • 成功时返回 0

  • 失败时返回错误码(非零值),常见的错误码包括:

    • EINVALmutexattr 参数无效。

    • ENOMEM:内存不足,无法初始化互斥锁。

    • EAGAIN:系统资源不足,无法初始化互斥锁。

互斥锁属性:

互斥锁的属性可以通过 pthread_mutexattr_initpthread_mutexattr_set 系列函数设置。以下是一些常用的属性:

  • PTHREAD_MUTEX_NORMAL:普通互斥锁,不允许递归锁定。

  • PTHREAD_MUTEX_RECURSIVE:递归互斥锁,允许同一个线程多次锁定。

  • PTHREAD_MUTEX_ERRORCHECK:错误检查互斥锁,对错误进行严格检查。

  • PTHREAD_MUTEX_ADAPTIVE_NP:自适应互斥锁(非标准属性,仅在某些系统上可用)。

如果使用默认属性(传入 NULL),互斥锁将被初始化为普通互斥锁(PTHREAD_MUTEX_NORMAL)。

示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

// 全局变量
int shared_data = 0;
pthread_mutex_t lock;

// 线程函数
void *thread_function(void *arg) {
    for (int i = 0; i < 100000; i++) {
        pthread_mutex_lock(&lock);  // 加锁
        shared_data++;
        pthread_mutex_unlock(&lock);  // 解锁
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    // 初始化互斥锁
    if (pthread_mutex_init(&lock, NULL) != 0) {
        perror("Failed to initialize mutex");
        return EXIT_FAILURE;
    }

    // 创建两个线程
    if (pthread_create(&thread1, NULL, thread_function, NULL) != 0) {
        perror("Failed to create thread 1");
        return EXIT_FAILURE;
    }

    if (pthread_create(&thread2, NULL, thread_function, NULL) != 0) {
        perror("Failed to create thread 2");
        return EXIT_FAILURE;
    }

    // 等待线程结束
    if (pthread_join(thread1, NULL) != 0) {
        perror("Failed to join thread 1");
        return EXIT_FAILURE;
    }

    if (pthread_join(thread2, NULL) != 0) {
        perror("Failed to join thread 2");
        return EXIT_FAILURE;
    }

    printf("Final shared data value: %d\n", shared_data);

    // 销毁互斥锁
    if (pthread_mutex_destroy(&lock) != 0) {
        perror("Failed to destroy mutex");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

输出示例

Final shared data value: 200000

2、上锁

在 Linux 系统中,pthread_mutex_lock 是 POSIX 线程库(pthread)提供的一个函数,用于对互斥锁(mutex)进行加锁操作。互斥锁是一种同步机制,用于保护共享资源,防止多个线程同时访问。

函数原型:
int pthread_mutex_lock(pthread_mutex_t *mutex);
  • pthread_mutex_lock 会尝试对指定的互斥锁进行加锁。

  • 如果互斥锁已经被其他线程锁定,调用 pthread_mutex_lock 的线程将被阻塞,直到互斥锁被释放。

  • 如果互斥锁是普通互斥锁(PTHREAD_MUTEX_NORMAL),同一个线程不能多次加锁,否则会引发死锁。

  • 如果互斥锁是递归互斥锁(PTHREAD_MUTEX_RECURSIVE),同一个线程可以多次加锁,但必须等价次数地解锁。

参数说明:
  • mutex:指向互斥锁的指针。该互斥锁必须已经通过 pthread_mutex_init 或静态初始化(PTHREAD_MUTEX_INITIALIZER)初始化。

返回值:
  • 成功时返回 0

  • 失败时返回错误码(非零值),常见的错误码包括:

    • EINVALmutex 参数无效。

    • EBUSY:互斥锁已经被其他线程锁定。

    • EDEADLK:发生死锁,例如尝试对已经由当前线程锁定的互斥锁再次加锁(普通互斥锁)。

    • EAGAIN:互斥锁类型为递归互斥锁,但递归次数超过限制。

示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

// 全局变量
int shared_data = 0;
pthread_mutex_t lock;

// 线程函数
void *thread_function(void *arg) {
    for (int i = 0; i < 100000; i++) {
        pthread_mutex_lock(&lock);  // 加锁
        shared_data++;
        pthread_mutex_unlock(&lock);  // 解锁
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    // 初始化互斥锁
    if (pthread_mutex_init(&lock, NULL) != 0) {
        perror("Failed to initialize mutex");
        return EXIT_FAILURE;
    }

    // 创建两个线程
    if (pthread_create(&thread1, NULL, thread_function, NULL) != 0) {
        perror("Failed to create thread 1");
        return EXIT_FAILURE;
    }

    if (pthread_create(&thread2, NULL, thread_function, NULL) != 0) {
        perror("Failed to create thread 2");
        return EXIT_FAILURE;
    }

    // 等待线程结束
    if (pthread_join(thread1, NULL) != 0) {
        perror("Failed to join thread 1");
        return EXIT_FAILURE;
    }

    if (pthread_join(thread2, NULL) != 0) {
        perror("Failed to join thread 2");
        return EXIT_FAILURE;
    }

    printf("Final shared data value: %d\n", shared_data);

    // 销毁互斥锁
    if (pthread_mutex_destroy(&lock) != 0) {
        perror("Failed to destroy mutex");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

输出示例

F
inal shared data value: 200000

3、尝试对互斥锁进行加锁操作,可用于判断是否加锁

在 Linux 系统中,pthread_mutex_trylock 是 POSIX 线程库提供的一个函数,用于尝试对互斥锁进行加锁操作。与 pthread_mutex_lock 不同,pthread_mutex_trylock 是非阻塞的,如果互斥锁已经被其他线程锁定,它会立即返回而不是阻塞当前线程。

函数原型

int pthread_mutex_trylock(pthread_mutex_t *mutex);
  • 如果互斥锁处于未锁定状态,pthread_mutex_trylock 会锁定互斥锁并返回 0

  • 如果互斥锁已经被其他线程锁定,pthread_mutex_trylock 会立即返回 EBUSY,而不会阻塞当前线程。

  • 对于递归互斥锁,pthread_mutex_trylock 会增加锁的递归计数,与 pthread_mutex_lock 行为相同。

参数说明:
  • mutex:指向互斥锁的指针。该互斥锁必须已经通过 pthread_mutex_init 或静态初始化(PTHREAD_MUTEX_INITIALIZER)初始化。

返回值:
  • 成功时返回 0,表示互斥锁已被当前线程成功锁定。

  • 失败时返回错误码(非零值),常见的错误码包括:

    • EBUSY:互斥锁已经被其他线程锁定,当前线程无法获取锁。

    • EINVALmutex 参数无效。

    • EAGAIN:互斥锁类型为递归互斥锁,但递归次数超过限制。

示例代码:
#include <stdio.h>
#include <pthread.h>

pthread_mutex_t mutex;

void *thread_function(void *arg) {
    if (pthread_mutex_trylock(&mutex) != 0) {
        if (errno == EBUSY) {
            printf("Thread was denied access to the mutex\n");
        } else {
            perror("pthread_mutex_trylock() error");
            exit(1);
        }
    } else {
        printf("Thread was granted the mutex\n");
        // 释放互斥锁
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_t thread;

    // 初始化互斥锁
    if (pthread_mutex_init(&mutex, NULL) != 0) {
        perror("pthread_mutex_init() error");
        exit(2);
    }

    // 创建线程
    if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
        perror("pthread_create() error");
        exit(3);
    }

    // 主线程尝试获取互斥锁
    if (pthread_mutex_trylock(&mutex) != 0) {
        if (errno == EBUSY) {
            printf("Main thread was denied access to the mutex\n");
        } else {
            perror("pthread_mutex_trylock() error");
            exit(4);
        }
    } else {
        printf("Main thread was granted the mutex\n");
        // 释放互斥锁
        pthread_mutex_unlock(&mutex);
    }

    // 等待线程结束
    if (pthread_join(thread, NULL) != 0) {
        perror("pthread_join() error");
        exit(5);
    }

    // 销毁互斥锁
    pthread_mutex_destroy(&mutex);
    return 0;
}

4、解锁

在 Linux 系统中,pthread_mutex_unlock 是 POSIX 线程库(pthread)提供的一个函数,用于解锁互斥锁(mutex)。解锁操作是线程同步机制中的重要部分,它允许其他线程获取互斥锁并访问共享资源。

函数原型:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
  • pthread_mutex_unlock 会解锁指定的互斥锁。

  • 如果互斥锁是普通互斥锁(PTHREAD_MUTEX_NORMAL),当前线程必须持有该锁,否则会返回错误。

  • 如果互斥锁是递归互斥锁(PTHREAD_MUTEX_RECURSIVE),当前线程可以多次加锁,但必须等价次数地解锁。

  • 解锁后,互斥锁的状态变为未锁定,其他线程可以尝试获取该锁。

参数说明:
  • mutex:指向互斥锁的指针。该互斥锁必须已经通过 pthread_mutex_init 或静态初始化(PTHREAD_MUTEX_INITIALIZER)初始化,并且当前线程必须持有该锁。

返回值:
  • 成功时返回 0

  • 失败时返回错误码(非零值),常见的错误码包括:

    • EINVALmutex 参数无效。

    • EPERM:当前线程未持有该互斥锁,或者尝试解锁一个未锁定的互斥锁。

    • EAGAIN:互斥锁类型为递归互斥锁,但递归次数超过限制。

示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

// 全局变量
int shared_data = 0;
pthread_mutex_t lock;

// 线程函数
void *thread_function(void *arg) {
    for (int i = 0; i < 100000; i++) {
        pthread_mutex_lock(&lock);  // 加锁
        shared_data++;
        pthread_mutex_unlock(&lock);  // 解锁
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    // 初始化互斥锁
    if (pthread_mutex_init(&lock, NULL) != 0) {
        perror("Failed to initialize mutex");
        return EXIT_FAILURE;
    }

    // 创建两个线程
    if (pthread_create(&thread1, NULL, thread_function, NULL) != 0) {
        perror("Failed to create thread 1");
        return EXIT_FAILURE;
    }

    if (pthread_create(&thread2, NULL, thread_function, NULL) != 0) {
        perror("Failed to create thread 2");
        return EXIT_FAILURE;
    }

    // 等待线程结束
    if (pthread_join(thread1, NULL) != 0) {
        perror("Failed to join thread 1");
        return EXIT_FAILURE;
    }

    if (pthread_join(thread2, NULL) != 0) {
        perror("Failed to join thread 2");
        return EXIT_FAILURE;
    }

    printf("Final shared data value: %d\n", shared_data);

    // 销毁互斥锁
    if (pthread_mutex_destroy(&lock) != 0) {
        perror("Failed to destroy mutex");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

输出示例

Final shared data value: 200000

5、销毁锁

在 Linux 系统中,pthread_mutex_destroy 是 POSIX 线程库提供的一个函数,用于销毁互斥锁(mutex)。销毁互斥锁后,该互斥锁将变为未初始化状态,可以重新初始化,但不能再直接使用。

函数原型:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
  • pthread_mutex_destroy 会销毁指定的互斥锁,释放与互斥锁相关的资源。

  • 销毁互斥锁后,该互斥锁将变为未初始化状态,可以重新初始化,但不能再直接使用。

  • 销毁一个未锁定的互斥锁是安全的。

  • 尝试销毁一个锁定的互斥锁,或者一个正在被其他线程使用的互斥锁,会导致未定义行为。

参数说明:
  • mutex:指向要销毁的互斥锁的指针。该互斥锁必须已经通过 pthread_mutex_init 或静态初始化(PTHREAD_MUTEX_INITIALIZER)初始化。

返回值:
  • 成功时返回 0

  • 失败时返回错误码(非零值),常见的错误码包括:

    • EBUSY:互斥锁当前处于锁定状态,或者有其他线程正在尝试锁定或解锁该互斥锁。

    • EINVALmutex 参数无效。

示例代码:
#include <stdio.h>
#include <pthread.h>

int main() {
    pthread_mutex_t mutex;

    // 初始化互斥锁
    if (pthread_mutex_init(&mutex, NULL) != 0) {
        perror("Failed to initialize mutex");
        return 1;
    }

    // 销毁互斥锁
    if (pthread_mutex_destroy(&mutex) != 0) {
        perror("Failed to destroy mutex");
        return 2;
    }

    printf("Mutex destroyed successfully.\n");
    return 0;
}

条件变量

1、初始化一个条件变量

在Linux系统中,pthread_cond_init 函数用于初始化一个条件变量。

函数原型:
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr);

pthread_cond_init 函数用于初始化条件变量cond,并根据cond_attr指定的属性进行配置。如果cond_attrNULL,则使用默认属性。

参数:
  • cond:指向要初始化的条件变量的指针。

  • cond_attr:指向条件变量属性的指针。如果为NULL,则使用默认属性。

返回值:
  • 成功时返回0

  • 失败时返回错误码。

注意事项:
  1. 条件变量必须与互斥锁一起使用,以避免竞态条件。

  2. 条件变量可以静态初始化,使用PTHREAD_COND_INITIALIZER常量。

  3. 在调用pthread_cond_destroy销毁条件变量之前,不能有线程正在等待该条件变量。

示例代码

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
​
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond;
​
void* worker(void* arg) {
    pthread_mutex_lock(&mut);
    printf("Worker: Waiting for condition\n");
    pthread_cond_wait(&cond, &mut);
    printf("Worker: Condition received\n");
    pthread_mutex_unlock(&mut);
    return NULL;
}
​
int main() {
    pthread_t thread;
    pthread_cond_init(&cond, NULL);
​
    pthread_create(&thread, NULL, worker, NULL);
​
    sleep(1); // 等待线程进入等待状态
    pthread_mutex_lock(&mut);
    printf("Main: Signaling condition\n");
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mut);
​
    pthread_join(thread, NULL);
    pthread_cond_destroy(&cond);
    return 0;
}

2、销毁一个条件变量

在Linux系统中,pthread_cond_destroy 函数用于销毁一个条件变量,释放与条件变量相关的资源。

函数原型:
int pthread_cond_destroy(pthread_cond_t *cond);

pthread_cond_destroy 函数用于销毁指定的条件变量cond,并释放与之相关的资源。销毁条件变量后,该条件变量将不再可用,任何对该条件变量的后续操作(如pthread_cond_waitpthread_cond_signal等)都将导致未定义行为。

参数:
  • cond:指向要销毁的条件变量的指针。

返回值:
  • 0:成功销毁条件变量。

  • EBUSY:有线程正在等待该条件变量,无法销毁。

  • 其他错误码:表示其他错误情况。

注意事项:
  1. 线程安全:在调用pthread_cond_destroy之前,必须确保没有线程正在等待该条件变量。如果有线程正在等待,调用pthread_cond_destroy将返回EBUSY错误。

  2. 静态初始化的条件变量:如果条件变量是静态初始化的(使用PTHREAD_COND_INITIALIZER),则不需要调用pthread_cond_destroy,因为它们会在程序退出时自动销毁。

  3. 动态初始化的条件变量:如果条件变量是通过pthread_cond_init动态初始化的,则必须在使用完毕后调用pthread_cond_destroy来释放资源。

  4. 互斥锁:条件变量通常与互斥锁一起使用。在销毁条件变量之前,应确保相关联的互斥锁已经解锁。

示例代码:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
​
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond;
​
void* worker(void* arg) {
    pthread_mutex_lock(&mut);
    printf("Worker: Waiting for condition\n");
    pthread_cond_wait(&cond, &mut);
    printf("Worker: Condition received\n");
    pthread_mutex_unlock(&mut);
    return NULL;
}
​
int main() {
    pthread_t thread;
    pthread_cond_init(&cond, NULL);
​
    pthread_create(&thread, NULL, worker, NULL);
​
    sleep(1); // 等待线程进入等待状态
    pthread_mutex_lock(&mut);
    printf("Main: Signaling condition\n");
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mut);
​
    pthread_join(thread, NULL);
​
    // 销毁条件变量
    if (pthread_cond_destroy(&cond) != 0) {
        perror("Failed to destroy condition variable");
    }
​
    return 0;
}

3、唤醒所有正在等待指定条件变量的线程

在Linux系统中,pthread_cond_broadcast 函数用于唤醒所有正在等待指定条件变量的线程。

函数原型:
int pthread_cond_broadcast(pthread_cond_t *cond);

pthread_cond_broadcast 函数会唤醒所有正在等待指定条件变量cond的线程。与pthread_cond_signal不同,pthread_cond_signal只唤醒一个等待的线程,而pthread_cond_broadcast会唤醒所有等待的线程。

参数:
  • cond:指向要操作的条件变量的指针。

返回值:
  • 0:成功唤醒所有等待的线程。

  • EINVAL:条件变量cond未初始化或已被销毁。

  • 其他错误码:表示其他错误情况。

注意事项:
  1. 互斥锁pthread_cond_broadcast通常与互斥锁一起使用。在调用pthread_cond_broadcast之前,调用线程必须持有与条件变量相关的互斥锁,并且在调用pthread_cond_broadcast之后,通常会释放该互斥锁。

  2. 线程状态:被唤醒的线程会重新尝试获取互斥锁。因此,调用pthread_cond_broadcast的线程需要确保在释放互斥锁之前,条件变量所保护的共享数据已经处于期望的状态。

  3. 性能考虑pthread_cond_broadcast会唤醒所有等待的线程,这可能会导致较高的上下文切换开销。如果只需要唤醒一个线程,建议使用pthread_cond_signal

  4. 线程安全:在调用pthread_cond_broadcast之前,必须确保条件变量cond已经正确初始化,并且没有被销毁。

示例代码:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
​
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond;
​
void* worker(void* arg) {
    int id = *(int*)arg;
    pthread_mutex_lock(&mut);
    printf("Worker %d: Waiting for condition\n", id);
    pthread_cond_wait(&cond, &mut);
    printf("Worker %d: Condition received\n", id);
    pthread_mutex_unlock(&mut);
    return NULL;
}
​
int main() {
    pthread_t threads[3];
    int ids[3] = {1, 2, 3};
​
    // 初始化条件变量
    pthread_cond_init(&cond, NULL);
​
    // 创建多个线程
    for (int i = 0; i < 3; i++) {
        pthread_create(&threads[i], NULL, worker, &ids[i]);
    }
​
    sleep(1); // 等待线程进入等待状态
​
    // 通知所有线程
    pthread_mutex_lock(&mut);
    printf("Main: Broadcasting condition\n");
    pthread_cond_broadcast(&cond);
    pthread_mutex_unlock(&mut);
​
    // 等待所有线程完成
    for (int i = 0; i < 3; i++) {
        pthread_join(threads[i], NULL);
    }
​
    // 销毁条件变量
    pthread_cond_destroy(&cond);
​
    return 0;
}
输出示例:
Worker 1: Waiting for condition
Worker 2: Waiting for condition
Worker 3: Waiting for condition
Main: Broadcasting condition
Worker 1: Condition received
Worker 2: Condition received
Worker 3: Condition received
使用场景:

pthread_cond_broadcast适用于以下场景:

  1. 生产者-消费者模型:当生产者生产了一批数据后,需要通知所有消费者线程进行消费。

  2. 线程池:当有新的任务到达时,需要唤醒所有空闲的线程来处理任务。

  3. 同步点:当多个线程需要在某个条件满足后同时继续执行时,可以使用pthread_cond_broadcast

4、唤醒一个正在等待指定条件变量的线程

在Linux系统中,pthread_cond_signal 函数用于唤醒一个正在等待指定条件变量的线程。它是线程间同步机制中的一个重要组成部分,常与互斥锁(pthread_mutex_t)和条件变量(pthread_cond_t)一起使用。

函数原型:
int pthread_cond_signal(pthread_cond_t *cond);

pthread_cond_signal 函数用于唤醒一个正在等待指定条件变量cond的线程。如果当前没有线程正在等待该条件变量,则pthread_cond_signal不会产生任何效果。

参数:
  • cond:指向要操作的条件变量的指针。

返回值:
  • 0:成功唤醒一个等待的线程。

  • EINVAL:条件变量cond未初始化或已被销毁。

  • 其他错误码:表示其他错误情况。

注意事项:
  1. 互斥锁
    • 在调用pthread_cond_signal之前,调用线程必须持有与条件变量相关的互斥锁。这是为了确保在唤醒线程之前,共享数据已经处于期望的状态。

    • 调用pthread_cond_signal后,通常会释放互斥锁,以便被唤醒的线程可以获取互斥锁并继续执行。

  2. 线程状态
    • 被唤醒的线程会重新尝试获取互斥锁。因此,调用pthread_cond_signal的线程需要确保在释放互斥锁之前,条件变量所保护的共享数据已经处于期望的状态。

    • 如果没有线程正在等待条件变量,pthread_cond_signal不会产生任何效果,也不会报错。

  3. 性能考虑
    • 如果只需要唤醒一个线程,pthread_cond_signal是合适的选择。

    • 如果需要唤醒所有等待的线程,应使用pthread_cond_broadcast

  4. 线程安全
    • 在调用pthread_cond_signal之前,必须确保条件变量cond已经正确初始化,并且没有被销毁。

    • 如果条件变量cond已被销毁,调用pthread_cond_signal将返回EINVAL错误。

示例代码:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
​
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond;
​
void* worker(void* arg) {
    int id = *(int*)arg;
    pthread_mutex_lock(&mut);
    printf("Worker %d: Waiting for condition\n", id);
    pthread_cond_wait(&cond, &mut);
    printf("Worker %d: Condition received\n", id);
    pthread_mutex_unlock(&mut);
    return NULL;
}
​
int main() {
    pthread_t threads[3];
    int ids[3] = {1, 2, 3};
​
    // 初始化条件变量
    pthread_cond_init(&cond, NULL);
​
    // 创建多个线程
    for (int i = 0; i < 3; i++) {
        pthread_create(&threads[i], NULL, worker, &ids[i]);
    }
​
    sleep(1); // 等待线程进入等待状态
​
    // 通知一个线程
    pthread_mutex_lock(&mut);
    printf("Main: Signaling condition\n");
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mut);
​
    // 等待所有线程完成
    for (int i = 0; i < 3; i++) {
        pthread_join(threads[i], NULL);
    }
​
    // 销毁条件变量
    pthread_cond_destroy(&cond);
​
    return 0;
}

输出示例

Worker 1: Waiting for condition
Worker 2: Waiting for condition
Worker 3: Waiting for condition
Main: Signaling condition
Worker 1: Condition received

5、线程等待某个条件变量

在Linux操作系统中,pthread_cond_wait 函数用于使线程等待某个条件变量,直到该条件变量被其他线程通过pthread_cond_signalpthread_cond_broadcast唤醒。它是线程间同步机制中的一个关键函数,通常与互斥锁(pthread_mutex_t)和条件变量(pthread_cond_t)一起使用。

函数原型:
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
参数:
  • cond:指向要等待的条件变量的指针。

  • mutex:指向与条件变量相关的互斥锁的指针。

功能:

pthread_cond_wait 函数使调用线程等待条件变量cond,直到该条件变量被其他线程通过pthread_cond_signalpthread_cond_broadcast唤醒。在调用pthread_cond_wait时,线程必须已经持有互斥锁mutex。函数的行为如下:

  1. 释放互斥锁:在进入等待状态之前,pthread_cond_wait会自动释放互斥锁mutex

  2. 等待条件变量:线程进入等待状态,直到条件变量被唤醒。

  3. 重新获取互斥锁:当条件变量被唤醒后,线程会重新尝试获取互斥锁mutex,只有在成功获取互斥锁后,线程才会继续执行。

返回值:
  • 0:成功唤醒并重新获取互斥锁。

  • EINVAL:条件变量cond或互斥锁mutex未初始化或已被销毁。

  • EDEADLK:调用线程没有持有互斥锁mutex

  • 其他错误码:表示其他错误情况。

注意事项:
  1. 互斥锁的持有
    • 在调用pthread_cond_wait之前,线程必须已经持有互斥锁mutex。如果线程没有持有互斥锁,调用pthread_cond_wait将返回EDEADLK错误。

    • pthread_cond_wait会自动释放互斥锁,因此在等待期间,其他线程可以获取该互斥锁。

  2. 虚假唤醒
    • pthread_cond_wait可能会发生虚假唤醒(spurious wakeup),即线程可能会在没有收到pthread_cond_signalpthread_cond_broadcast的情况下被唤醒。因此,建议在使用pthread_cond_wait时,将其放在循环中,并在循环中检查条件是否真正满足。

  3. 线程安全
    • 在调用pthread_cond_wait之前,必须确保条件变量cond和互斥锁mutex已经正确初始化,并且没有被销毁。

  4. 性能考虑
    • pthread_cond_wait会阻塞线程,直到条件变量被唤醒。因此,建议在条件变量被唤醒后尽快完成必要的操作,以避免其他线程长时间等待。

示例代码:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
​
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond;
int data_ready = 0;
​
void* producer(void* arg) {
    pthread_mutex_lock(&mut);
    printf("Producer: Preparing data\n");
    sleep(2); // 模拟数据准备时间
    data_ready = 1;
    printf("Producer: Data ready, signaling condition\n");
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mut);
    return NULL;
}
​
void* consumer(void* arg) {
    pthread_mutex_lock(&mut);
    while (!data_ready) { // 防止虚假唤醒
        printf("Consumer: Waiting for condition\n");
        pthread_cond_wait(&cond, &mut);
    }
    printf("Consumer: Condition received, processing data\n");
    pthread_mutex_unlock(&mut);
    return NULL;
}
​
int main() {
    pthread_t producer_thread, consumer_thread;
​
    // 初始化条件变量
    pthread_cond_init(&cond, NULL);
​
    // 创建生产者和消费者线程
    pthread_create(&producer_thread, NULL, producer, NULL);
    pthread_create(&consumer_thread, NULL, consumer, NULL);
​
    // 等待线程完成
    pthread_join(producer_thread, NULL);
    pthread_join(consumer_thread, NULL);
​
    // 销毁条件变量
    pthread_cond_destroy(&cond);
​
    return 0;
}
输出示例:
Consumer: Waiting for condition
Producer: Preparing data
Producer: Data ready, signaling condition
Consumer: Condition received, processing data

信号量

1、初始化信号量

在 Linux 系统中,sem_init 是 POSIX 线程库(pthread)提供的一个函数,用于初始化一个无名信号量(unnamed semaphore)。

函数原型:
int sem_init(sem_t *sem, int pshared, unsigned int value);
  • sem_init 初始化一个无名信号量,使其可以用于线程同步。

  • 初始化后的信号量可以用于 sem_waitsem_trywaitsem_postsem_destroy 等函数。

  • 如果 pshared 为非零值,信号量必须位于共享内存区域(如通过 shm_openmmapshmget 创建的共享内存)。

  • 信号量在初始化后可以被多个线程或进程使用,直到被销毁。

参数说明:
  • sem:指向要初始化的信号量的指针。

  • pshared:指定信号量是否在进程间共享。如果为 0,信号量仅在当前进程的线程间共享;如果为非零值,信号量可在多个进程间共享。

  • value:信号量的初始值。

返回值:
  • 成功时返回 0

  • 失败时返回 -1,并设置 errno 以指示错误:

    • EINVALvalue 超过 SEM_VALUE_MAX

    • ENOSYSpshared 为非零值,但系统不支持进程间共享信号量。

注意事项:
  • 不能对已经初始化的信号量再次调用 sem_init,否则会导致未定义行为。

  • 在销毁信号量之前,应确保所有线程或进程不再使用该信号量。

示例代码:
#include <stdio.h>
#include <semaphore.h>
#include <stdlib.h>

int main() {
    sem_t sem;
    if (sem_init(&sem, 0, 1) != 0) {
        perror("sem_init failed");
        return 1;
    }

    // 使用信号量
    sem_wait(&sem);
    printf("Semaphore acquired\n");
    sem_post(&sem);

    // 销毁信号量
    sem_destroy(&sem);
    return 0;
}

通过 sem_init 初始化信号量,可以实现线程或进程间的同步,确保对共享资源的访问是安全的。

2、P操作

在 Linux 系统中,sem_wait 函数用于对信号量进行锁定操作。

函数原型1:
int sem_wait(sem_t *sem);
  • 信号量锁定:sem_wait 函数会对指定的信号量 sem 执行锁定操作。

  • 阻塞行为:如果信号量的值大于零,sem_wait 会立即将信号量的值减一,然后函数返回。如果信号量的值为零,调用线程将被阻塞,直到信号量的值变为正数,或者被信号中断。

  • 信号中断:该函数是可以被信号中断的。

返回值:
  • 成功:如果成功锁定信号量,sem_wait 函数返回 0。

  • 失败:如果发生错误,函数返回 -1,并设置 errno 来指示错误原因。

    • EINTR:如果在等待信号量时被信号中断。

    • EINVAL:如果 sem 参数指向的信号量无效。

示例代码:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>

sem_t sem;

void* thread_func(void* arg) {
    printf("Thread is waiting for semaphore.\n");
    sem_wait(&sem); // 等待信号量
    printf("Thread has acquired semaphore.\n");
    return NULL;
}

int main() {
    pthread_t thread;
    sem_init(&sem, 0, 0); // 初始化信号量,初始值为0

    pthread_create(&thread, NULL, thread_func, NULL);

    sleep(2); // 主线程等待2秒后释放信号量
    printf("Main thread posting semaphore.\n");
    sem_post(&sem); // 释放信号量

    pthread_join(thread, NULL);
    sem_destroy(&sem);
    return 0;
}

在 Linux 系统中,sem_trywait 函数是 POSIX 信号量库中的一个非阻塞版本的信号量等待操作,用于尝试获取一个信号量而不会阻塞调用线程。

函数原型:
int sem_trywait(sem_t *sem);
功能描述:
  • 非阻塞尝试获取信号量:sem_trywait 函数尝试对指定的信号量 sem 执行锁定操作。如果信号量的当前值大于零,它会立即将信号量的值减一并返回。如果信号量的值为零,函数不会阻塞,而是立即返回错误。

  • 信号量状态:如果调用成功,信号量的状态将被锁定。如果调用失败,信号量的状态保持不变。

返回值:
  • 成功:返回 0。

  • 失败:返回 -1,并设置 errno 以指示错误。

    • EAGAIN:信号量已经被锁定,无法立即获取。

    • EINVALsem 参数指向的信号量无效。

    • EINTR:调用被信号中断。

示例代码:
#include <stdio.h>
#include <semaphore.h>
#include <errno.h>

sem_t sem;

void* thread_func(void* arg) {
    if (sem_trywait(&sem) == -1) {
        if (errno == EAGAIN) {
            printf("Semaphore is already locked, cannot acquire immediately.\n");
        } else {
            perror("sem_trywait failed");
        }
    } else {
        printf("Semaphore acquired successfully.\n");
    }
    return NULL;
}

int main() {
    if (sem_init(&sem, 0, 1) == -1) {
        perror("sem_init failed");
        return 1;
    }

    pthread_t thread;
    pthread_create(&thread, NULL, thread_func, NULL);

    pthread_join(thread, NULL);
    sem_destroy(&sem);
    return 0;
}

3、V操作

在 Linux 系统中,sem_post 函数用于对信号量进行解锁操作,即增加信号量的值。

函数原型:
int sem_post(sem_t *sem);
  • 解锁信号量:sem_post 函数对指向的信号量 sem 执行解锁操作,即将信号量的值加一。

  • 唤醒等待线程:如果信号量的值因此操作变为大于零,则会唤醒一个因调用 sem_wait 而阻塞的线程或进程。

  • 调度策略:如果系统支持进程调度选项(如 SCHED_FIFOSCHED_RR),则会根据调度策略和参数选择优先级最高的等待线程进行唤醒。

返回值:
  • 成功:返回 0。

  • 失败:返回 -1,信号量的值保持不变,并设置 errno 以指示错误。

    • EINVALsem 参数指向的信号量无效。

    • EOVERFLOW:信号量的值超过了系统允许的最大值。

示例代码:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>

sem_t sem;

void* thread_func(void* arg) {
    printf("Thread is waiting for semaphore.\n");
    sem_wait(&sem); // 等待信号量
    printf("Thread has acquired semaphore.\n");
    return NULL;
}

int main() {
    if (sem_init(&sem, 0, 0) != 0) {
        perror("sem_init failed");
        return 1;
    }

    pthread_t thread;
    pthread_create(&thread, NULL, thread_func, NULL);

    sleep(2); // 主线程等待2秒后释放信号量
    printf("Main thread posting semaphore.\n");
    if (sem_post(&sem) != 0) {
        perror("sem_post failed");
    }

    pthread_join(thread, NULL);
    sem_destroy(&sem);
    return 0;
}

4、获取信号量的值

在 Linux 系统中,sem_getvalue 函数用于获取信号量的当前值。

函数原型:
int sem_getvalue(sem_t *restrict sem, int *restrict sval);
  • 获取信号量值:sem_getvalue 函数将信号量 sem 的当前值存储到 sval 指向的整数变量中。

  • 阻塞线程的处理:如果有一个或多个线程或进程正在使用 sem_wait 等待该信号量,POSIX 标准允许返回两种结果:

    • 返回 0。

    • 返回一个负值,其绝对值表示当前阻塞在 sem_wait 中的线程或进程数量。 在 Linux 系统中,选择返回 0。

返回值:
  • 成功:返回 0。

  • 失败:返回 -1,并设置 errno 以指示错误。

    • EINVALsem 参数指向的信号量无效。

示例代码:
#include <stdio.h>
#include <semaphore.h>

int main() {
    sem_t semaphore;
    int value;

    // 初始化信号量
    if (sem_init(&semaphore, 0, 1) != 0) {
        perror("sem_init failed");
        return 1;
    }

    // 获取信号量的当前值
    if (sem_getvalue(&semaphore, &value) != 0) {
        perror("sem_getvalue failed");
        return 1;
    }

    printf("Current value of semaphore: %d\n", value);

    // 销毁信号量
    sem_destroy(&semaphore);
    return 0;
}

该代码初始化一个信号量,获取其当前值并打印,最后销毁信号量。

5、删除信号量

在 Linux 系统中,sem_destroy 函数用于销毁一个已经初始化的 POSIX 信号量(sem_t)。销毁信号量可以释放与之相关的系统资源。

函数原型:
int sem_destroy(sem_t *sem);
  • 销毁信号量:sem_destroy 函数用于销毁指定的信号量 sem,释放与之相关的系统资源。

  • 未销毁的信号量:如果信号量未被销毁,它仍然可以被其他线程或进程使用。销毁信号量后,不能再对它进行任何操作(如 sem_waitsem_post 等),否则会导致未定义行为。

返回值:
  • 成功:返回 0。

  • 失败:返回 -1,并设置 errno 以指示错误。

    • EINVALsem 参数指向的信号量无效。

    • EBUSY:信号量当前仍有线程或进程阻塞在 sem_wait 上,无法销毁。

示例代码:
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>

sem_t sem;

void* thread_func(void* arg) {
    printf("Thread is waiting for semaphore.\n");
    sem_wait(&sem); // 等待信号量
    printf("Thread has acquired semaphore.\n");
    return NULL;
}

int main() {
    if (sem_init(&sem, 0, 0) != 0) {
        perror("sem_init failed");
        return 1;
    }

    pthread_t thread;
    pthread_create(&thread, NULL, thread_func, NULL);

    sleep(2); // 主线程等待2秒后释放信号量
    printf("Main thread posting semaphore.\n");
    sem_post(&sem); // 释放信号量

    pthread_join(thread, NULL);

    // 销毁信号量
    if (sem_destroy(&sem) != 0) {
        perror("sem_destroy failed");
        return 1;
    }

    printf("Semaphore destroyed successfully.\n");
    return 0;
}

三、线程属性

1、初始化线程属性对象

在 Linux 系统中,pthread_attr_init 函数用于初始化线程属性对象(pthread_attr_t),以便在创建线程时指定线程的属性。

函数原型:
int pthread_attr_init(pthread_attr_t *attr);
  • 初始化线程属性对象:pthread_attr_init 函数将 attr 指向的线程属性对象初始化为默认值。初始化后,可以使用相关的函数(如 pthread_attr_setdetachstatepthread_attr_setstacksize 等)修改这些属性。

  • 默认属性:初始化后的线程属性对象具有以下默认值:

    • 分离状态:PTHREAD_CREATE_JOINABLE(线程可以被其他线程等待)。

    • 调度策略:SCHED_OTHER(普通调度策略)。

    • 调度优先级:0。

    • 栈大小:系统默认值(通常是 2MB)。

    • 栈保护区域大小:系统默认值(通常是 4KB)。

  • 多次初始化:对已经初始化的线程属性对象再次调用 pthread_attr_init 会导致未定义行为。

返回值:
  • 成功:返回 0。

  • 失败:返回非零错误码。在 Linux 系统中,pthread_attr_init 函数通常不会失败,但为了可移植性和未来兼容性,建议处理可能的错误返回。

    • ENOMEM:在某些实现中,如果内存不足,可能会返回此错误。但在 Linux 系统中,该函数通常不会失败。

示例代码:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>

void* thread_func(void* arg) {
    printf("Thread is running.\n");
    return NULL;
}

int main() {
    pthread_t thread;
    pthread_attr_t attr;

    // 初始化线程属性对象
    if (pthread_attr_init(&attr) != 0) {
        perror("pthread_attr_init failed");
        return 1;
    }

    // 设置线程属性(例如,设置栈大小)
    if (pthread_attr_setstacksize(&attr, 1024 * 1024) != 0) {
        perror("pthread_attr_setstacksize failed");
        return 1;
    }

    // 创建线程
    if (pthread_create(&thread, &attr, thread_func, NULL) != 0) {
        perror("pthread_create failed");
        return 1;
    }

    // 等待线程结束
    if (pthread_join(thread, NULL) != 0) {
        perror("pthread_join failed");
        return 1;
    }

    // 销毁线程属性对象
    if (pthread_attr_destroy(&attr) != 0) {
        perror("pthread_attr_destroy failed");
        return 1;
    }

    printf("Thread completed successfully.\n");
    return 0;
}

2、设置线程属性对象的分离状态属性

在 Linux 系统中,pthread_attr_setdetachstate 函数用于设置线程属性对象的分离状态属性。

函数原型

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
  • 设置分离状态:pthread_attr_setdetachstate 函数将线程属性对象 attr 的分离状态设置为 detachstate 指定的值。

  • 分离状态的作用:分离状态决定了使用该属性对象创建的线程是处于可连接状态(PTHREAD_CREATE_JOINABLE)还是分离状态(PTHREAD_CREATE_DETACHED)。

    • PTHREAD_CREATE_JOINABLE:线程结束时,其资源不会自动释放,需要其他线程通过 pthread_join 回收资源。

    • *PTHREAD_CREATE_DETACHED:线程结束时,其资源会自动释放,无需其他线程回收资源。

参数:
  • attr:指向线程属性对象的指针。

  • detachstate:指定线程的分离状态,可以是以下值之一:

    • PTHREAD_CREATE_JOINABLE:线程可连接。

    • PTHREAD_CREATE_DETACHED:线程分离。

返回值:
  • 成功:返回 0。

  • 失败:返回非零错误码。

    • EINVALdetachstate 参数无效。

示例代码:
#include <stdio.h>
#include <pthread.h>

void* thread_func(void* arg) {
    printf("Thread is running.\n");
    return NULL;
}

int main() {
    pthread_t thread;
    pthread_attr_t attr;

    // 初始化线程属性对象
    if (pthread_attr_init(&attr) != 0) {
        perror("pthread_attr_init failed");
        return 1;
    }

    // 设置线程的分离状态为分离状态
    if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) {
        perror("pthread_attr_setdetachstate failed");
        return 1;
    }

    // 创建线程
    if (pthread_create(&thread, &attr, thread_func, NULL) != 0) {
        perror("pthread_create failed");
        return 1;
    }

    // 销毁线程属性对象
    if (pthread_attr_destroy(&attr) != 0) {
        perror("pthread_attr_destroy failed");
        return 1;
    }

    printf("Thread created successfully.\n");
    return 0;
}

3、获取线程属性对象中的调度参数属性

在 Linux 系统中,pthread_attr_getschedparam 函数用于获取线程属性对象中的调度参数属性。

函数原型:
int pthread_attr_getschedparam(const pthread_attr_t *restrict attr, struct sched_param *restrict param);
  • 获取调度参数pthread_attr_getschedparam 函数从线程属性对象 attr 中获取调度参数,并将其存储到 param 指向的 struct sched_param 结构中。

  • 调度参数结构:调度参数通过 struct sched_param 结构体表示,通常包含以下成员:

    • sched_priority:线程的调度优先级。

  • 调度策略:调度参数通常与线程的调度策略(如 SCHED_FIFOSCHED_RRSCHED_OTHER 等)结合使用。

参数:
  • attr:指向线程属性对象的指针,该对象必须已经通过 pthread_attr_init 初始化。

  • param:指向 struct sched_param 结构体的指针,用于存储获取的调度参数。

返回值:
  • 成功:返回 0。

  • 失败:返回非零错误码。

错误码:
  • EINVALattr 参数未引用已初始化的线程属性对象。

示例代码:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>

int main(void) {
    pthread_attr_t attr;
    struct sched_param param;

    // 初始化线程属性对象
    if (pthread_attr_init(&attr) != 0) {
        perror("pthread_attr_init failed");
        exit(1);
    }

    // 设置调度参数(示例)
    param.sched_priority = 5;
    if (pthread_attr_setschedparam(&attr, &param) != 0) {
        perror("pthread_attr_setschedparam failed");
        exit(2);
    }

    // 获取调度参数
    if (pthread_attr_getschedparam(&attr, &param) != 0) {
        perror("pthread_attr_getschedparam failed");
        exit(3);
    }

    printf("Retrieved scheduling priority: %d\n", param.sched_priority);

    // 销毁线程属性对象
    if (pthread_attr_destroy(&attr) != 0) {
        perror("pthread_attr_destroy failed");
        exit(4);
    }

    return 0;
}

4、设置线程属性对象的调度参数

在 Linux 系统中,pthread_attr_setschedparam 函数用于设置线程属性对象的调度参数。

函数原型:
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
功能描述:
  • 设置调度参数pthread_attr_setschedparam 函数将线程属性对象 attr 的调度参数设置为 param 指向的 struct sched_param 结构体中的值。

  • 调度参数结构:调度参数通过 struct sched_param 结构体表示,通常包含以下成员:

    • sched_priority:线程的调度优先级。

  • 调度策略:调度参数通常与线程的调度策略结合使用,调度策略可以通过 pthread_attr_setschedpolicy 设置。

参数:
  • attr:指向线程属性对象的指针。

  • param:指向 struct sched_param 结构体的指针,该结构体包含要设置的调度参数。

返回值:
  • 成功:返回 0。

  • 失败:返回非零错误码。

错误码:
  • EINVALparam 中指定的优先级对于当前的调度策略无效。

  • ENOTSUP:指定的调度参数不被支持。

示例代码

#include <stdio.h>
#include <pthread.h>
#include <sched.h>
#include <stdlib.h>
#include <errno.h>
​
void* thread_function(void *arg) {
    // 线程执行的代码
}
​
int main() {
    pthread_t thread;
    pthread_attr_t attr;
    struct sched_param param;
​
    // 初始化线程属性
    if (pthread_attr_init(&attr) != 0) {
        perror("pthread_attr_init");
        exit(1);
    }
​
    // 设置线程调度策略为 SCHED_FIFO
    if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0) {
        perror("pthread_attr_setschedpolicy");
        exit(1);
    }
​
    // 设置线程优先级
    param.sched_priority = 99; // 范围通常是 1 到 99,具体取决于系统配置
    if (pthread_attr_setschedparam(&attr, &param) != 0) {
        perror("pthread_attr_setschedparam");
        exit(1);
    }
​
    // 创建线程
    if (pthread_create(&thread, &attr, thread_function, NULL) != 0) {
        perror("pthread_create");
        exit(1);
    }
​
    // 等待线程结束
    if (pthread_join(thread, NULL) != 0) {
        perror("pthread_join");
        exit(1);
    }
​
    // 销毁线程属性
    if (pthread_attr_destroy(&attr) != 0) {
        perror("pthread_attr_destroy");
        exit(1);
    }
​
    return 0;
}

参考资源:https://download.youkuaiyun.com/download/2403_82436914/90610799?spm=1001.2014.3001.5503

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值