这篇文章上次修改于 448 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

创建线程

创建变量储存线程 id

pthread_t pth ;//线程id

(可选)线程属性

(可选)可自定义线程属性,也可使用默认 NULL

//自定义线程属性

pthread_attr_t attr;// 初始化线程属性 && creat 也可传 NULL

//初始化线程属性
int pthread_attr_init(pthread_attr_t *attr);
    //销毁线程属性所占用的资源
    pthread_attr_destroy();

//设置线程属性,分离 or 非分离
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

//获取程属性,分离 or 非分离
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
    // detachstate:
    //     PTHREAD_CREATE_DETACHED(分离线程)
    //     PTHREAD _CREATE_JOINABLE(非分离线程)

int pthread_attr_getdetachstate(const pthread_attr_t *__attr, int *__detachstate);
//获取线程状态保存到第二个参数
    // 判断线程状态

if (detachstate == PTHREAD_CREATE_DETACHED) //判断分离
    printf("thread detached\n");
else if (detachstate == PTHREAD_CREATE_JOINABLE)//判断非分离
    printf("thread join\n");
else
    printf("thread unknown\n");

creat 线程

pthread*create(&pth, NULL, (void *)func, (void \_)argv);
//(指定线程 id,线程属性,执行函数,函数参数)


int pthread_create(pthread_t *__restrict__ __newthread, const pthread_attr_t *__restrict__ __attr, void *(*__start_routine)(void *), void *__restrict__ __arg)

线程其他用法

pthread_exit()//退出线程
pthread_join()//阻塞等待回收线程 ,第二个参数保存返回值
pthread_cancel() //取消线程(到达取消点时取消)
pthread_self();//获取线程id

互斥量使用

初始化互斥量

1. 静态初始化

如果互斥锁 mutex 是静态分配的(定义在全局,或加了 static 关键字修饰),可以直接 使用宏进行初始化。(可移植性差)

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

2. 动态初始化

局部变量应采用动态初始化。

    pthread_mutex_init(&lock, NULL)//默认属性(线程间共享)

正常 创建线程

每个线程中

pthread_mutex_lock(&lock);或 pthread_mutex_trylock(&lock);
/*------------  使用 -------------*/
pthread_mutex_unlock(&lock);

销毁互斥量(仅动态初始化)

pthread_mutex_destroy(&lock);

条件变量 pthread_cond_t

经常结合互斥量使用,且与互斥量使用方式类似

条件变量初始化

静态初始化

pthread_cond_t cond=THREAD_COND_INITIALIZE;

动态初始化

pthread_cond_init();

通知与等待


pthread_cond_signal();//只保证唤醒至少一条遭到阻塞的线程
pthread_cond_broadcast();//会唤醒所有遭阻塞的线程



pthread_cond_wait();//函数将阻塞一线程,直至收到条件变量 cond的通知。
pthread_cond_timedwait();//参数来指定休眠时间的上限。
    /*
    参数abstime是一个timespec类型的结构(见23.4.2节),用以指定自Epoch(参考10.1节)以来以秒和纳秒(nanosecond)为单位表示的绝对(absolute)时间。如果abstime指定的时间间隔到期且无相关条件变量的通知,则返回ETIMEOUT错误
    */

生产者消费者模型之互斥量

生产者(子线程)

  1. 加锁
  2. 判断缓冲区容量
    空闲/充足:

生产+操作+通知

  1. 解锁

消费者(主线程)

一定要先加锁再判断

  1. 加锁
  2. 判断
    缓冲区空:堵塞
  3. 操作
  4. 解锁
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <wait.h>
#include <errno.h>
#include <pthread.h>

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
char header[10] = {0}; //缓冲区大小10
void *producter(void *argv)
{
    //生产者
    //1. 加锁
    //2. 判断缓冲区容量
    //      空闲/充足:
    //          生产+操作+通知
    //3. 解锁

    char temp[30] = {0};
    do
    {

        //满了不生产
        pthread_mutex_lock(&mutex);
        if (strlen(header) != 9) //判断是否满
        {
            printf("i am producter%ld\n", pthread_self());
            strcpy(temp, "aaa");
            strcat(header, temp);
            pthread_cond_signal(&cond);
        }
        pthread_mutex_unlock(&mutex);

        memset(temp, 0, sizeof(char) * 30);

        sleep(rand() % 3);
    } while (1);
}

void *customer(void *argv)
{
    //消费者
    //1.加锁
    //2.判断
    //      缓冲区空:堵塞
    //3.操作
    //4.解锁
    do
    {
        pthread_mutex_lock(&mutex);
        while (strlen(header) == 0) //空了不消费
            pthread_cond_wait(&cond, &mutex);
        printf("               %s\n", header);
        header[strlen(header) - 3] = '\0';
        pthread_mutex_unlock(&mutex);
        printf("                       i am customer %ld\n", pthread_self());
        sleep(rand() % 3);
    } while (1);
}

int main()
{
    pthread_t tid[12];
    srand(time(NULL));
    int i = 0;
    for (i = 0; i < 5; i++)
        pthread_create(&tid[i], NULL, customer, NULL);
    for (i = 0; i < 5; i++)
        pthread_create(&tid[i], NULL, producter, NULL);
    sleep(100);
}

Posix 无名信号量

可用于线程间也可用于进程间
sem_init 函数参 2:pshared
0 用于线程间;
非 0(一般为 1)用于进程间

头文件

include<semaphore.h>

变量类型

sem_t 类型

sem_t sem;//规定信号量 sem 不能 < 0

常用函数

sem_init 函数
sem_destroy 函数
sem_wait 函数
sem_post 函数
sem_wait:   1. 信号量大于 0,则信号量--
|           2. 信号量等于 0,造成线程阻塞(类比 pthread_mutex_lock)
|
|
sem_post: 将信号量++,同时唤醒阻塞在信号量上的线程 (类比 pthread_mutex_unlock)
sem_trywait 函数
sem_timedwait 函数

函数介绍

sem_init 函数
int sem_init(sem_t *sem, int pshared, unsigned int value);
参 1:sem 信号量
参 2:pshared 取 0 用于线程间;
              取非 0(一般为 1)用于进程间
参 3:value 指定信号量初值

sem_destroy 函数
int sem_destroy(sem_t *sem);

sem_wait 函数
1. 信号量大于 0,则信号量--
2. 信号量等于 0,造成线程阻塞(类比 pthread_mutex_lock)
int sem_wait(sem_t *sem);

sem_post 函数
给信号量解锁 ++
int sem_post(sem_t *sem);

sem_trywait 函数
尝试对信号量加锁 -- (与 sem_wait 的区别类比 lock 和 trylock)
int sem_trywait(sem_t *sem);

sem_timedwait 函数
限时尝试对信号量加锁

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
参 2:abs_timeout 采用的是绝对时间。
        定时 1 秒:
                time_t cur = time(NULL); 获取当前时间。
                struct timespec t; 定义 timespec 结构体变量 t
                t.tv_sec = cur+1; 定时 1 秒
                t.tv_nsec = t.tv_sec +100;
                sem_timedwait(&sem, &t); 传参

生产者消费者模型之信号量

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <wait.h>
#include <errno.h>
#include <pthread.h>

char header[10] = {0}; //缓冲区大小10
sem_t fre;
sem_t used;
void *producter(void *argv)
{
    char temp[30] = {0};
    do
    {
        sem_wait(&fre);//fre--  为负则堵塞
        strcpy(temp, "aaa");
        strcat(header, temp);
        sem_post(&used);//used++
        memset(temp, 0, sizeof(char) * 30);

        sleep(rand() % 3);
    } while (1);
}

void *customer(void *argv)
{
    do
    {
        sem_wait(&used);//used-- 为负堵塞
        printf("%s\n", header);
        header[strlen(header - 3)] = '\0';
        sem_post(&fre);//fre++
        sleep(rand() % 3);
    } while (1);
}

int main()
{
    pthread_t tid[12];
    srand(time(NULL));

    sem_init(&used, 0, 0);
    sem_init(&fre, 0, 3);//最多生产3个数据

    int i = 0;
    for (i = 0; i < 5; i++)
        pthread_create(&tid[i], NULL, customer, NULL);
    for (i = 0; i < 5; i++)
        pthread_create(&tid[i], NULL, producter, NULL);
    sleep(15);

    sem_destroy(&used);
    sem_destroy(&fre);
}

读写锁

写独占、读共享

读锁、写锁并行阻塞,写锁优先级高

定义一个读写锁变量

pthread_rwlock_t 类型

pthread_rwlock_t rwlock;

主要应用函数

pthread_rwlock_init 函数
pthread_rwlock_destroy 函数

pthread_rwlock_rdlock 函数
pthread_rwlock_wrlock 函数
    pthread_rwlock_tryrdlock 函数
    pthread_rwlock_trywrlock 函数
pthread_rwlock_unlock 函数

线程池

/*        待完成         */