用互斥锁、信号量、条件变量实现线程同步

什么是线程同步?

线程同步指的是当一个线程在对某个临界资源进行操作时,其他线程都不可以对这个资源进行操作,直到该线程完成操作。

pthread_create()

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);//用于创建新的线程

//*thread,指向线程标识符的指针,用于存储新线程的标识符

//attr,通常位NULL

//start_routine,指向线程主函数的指针,新线程将从这个函数开始执行

//arg,传递给 start_routine 的参数

//成功返回0,错误返回错误码

pthread_join()

int pthread_join(pthread_t thread, void **retval);//用于等待一个线程结束并回收其资源

//thread,要等待的线程的标识符

//retval,存储被等待线程的返回值的地址。如果不关心返回值,可以传递 NULL

//成功返回0,错误返回错误码

互斥锁

pthread_mutex_init()

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);//初始化互斥量

//mutex,指向要初始化的互斥锁的指针

//attr,指向线程属性对象的指针。如果传递 NULL,则使用默认的属性

//成功返回0,错误返回错误码

pthread_mutex_lock()

int pthread_mutex_lock(pthread_mutex_t *mutex); //用于对指定的互斥量进行加锁

//mutex,指向互斥量的指针

//成功返回0,错误返回错误码

pthread_mutex_unlock()

int pthread_mutex_unlock(pthread_mutex_t *mutex); //用于解锁之前由 pthread_mutex_lock 函数锁定的互斥量

//mutex,指向互斥量的指针

//成功返回0,错误返回错误码

 pthread_mutex_destroy()

int pthread_mutex_destroy(pthread_mutex_t *mutex); //用于销毁互斥锁

//mutex,指向待销毁的互斥锁的指针

//成功返回0,错误返回错误码

实践

主线程和函数线程模拟访问打印机,主线程输出第一个字符‘a’表示开始使用打印机,输出第二个字符‘a’表示结束使用,函数线程操作与主线程相同。

#include<iostream>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
//#include <semaphore.h>

using namespace std;

pthread_mutex_t mutex;

void *thread_fun(void *arg)
{
    int i = 0;
    for (; i < 5; i++)
    {
        pthread_mutex_lock(&mutex);
        write(1, "B", 1);
        // cout << "B";fflush(stdout);
        sleep(rand() % 3); // 随机睡眠一段时间,用于模拟线程在做其他事情
         write(1, "B", 1);
        //cout << "B"; fflush(stdout);
        pthread_mutex_unlock(&mutex);
        sleep(rand() % 3);
    }

    pthread_exit(NULL);
}

int main()
{
    pthread_t id;

    pthread_mutex_init(&mutex, NULL);
    pthread_create(&id, NULL, thread_fun, NULL);

    int i = 0;
    for (; i < 5; i++)
    {
        pthread_mutex_lock(&mutex);
        write(1, "A", 1);
        //cout << "A"; fflush(stdout);
        sleep(rand() % 3);
        write(1, "A", 1);
        //cout << "A"; fflush(stdout);
        pthread_mutex_unlock(&mutex);
        sleep(rand() % 3);
    }

    pthread_join(id, NULL);

    pthread_mutex_destroy(&mutex);
    cout << endl;

    exit(0);
}

输出结果:AABBAABBAABBAABBAABB

信号量

sem_init()

int sem_init(sem_t *sem, int pshared, unsigned int value); //初始化信号量

//sem,指向要初始化的信号量的指针

//value,信号量的初始值

sem_wait()

int sem_wait(sem_t *sem);//等待信号量

//sem,指向要初始化的信号量的指针

sem_post()

 int sem_post(sem_t *sem);//释放信号量

//sem,指向要初始化的信号量的指针

sem_destroy()

 int sem_destroy(sem_t *sem);//销毁信号量

//sem,指向要初始化的信号量的指针

实践

实现一个基于线程和信号量的简单的生产者-消费者模型,主线程用于从用户输入中获取数据,子线程读取数据并将其写入文件。

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <fcntl.h>

using namespace std;

char buff[128] = {0};

sem_t sem1;
sem_t sem2;

void *PthreadFun(void *arg)
{
    int fd = open("a.txt", O_RDWR | O_CREAT, 0664);
    if (fd == -1)
    {
        cout << "open failed" << endl;
    }

    // 函数线程完成将用户输入的数据存储到文件中
    while (1)
    {
        sem_wait(&sem2);

        if (strncmp(buff, "end", 3) == 0)
        {
            break;
        }

        write(fd, buff, strlen(buff));
        memset(buff, 0, 128);

        sem_post(&sem1);
    }

    sem_destroy(&sem1);
    sem_destroy(&sem2);

    return NULL;
}

int main()
{
    sem_init(&sem1, 0, 1);
    sem_init(&sem2, 0, 0);

    pthread_t id;
    int res = pthread_create(&id, NULL, PthreadFun, NULL);

    // 主线程完成获取用户数据的数据,并存储在全局数组 buff 中
    while (1)
    {
        sem_wait(&sem1);

        cout << "please input data: " << endl;

        //fgets(buff, 128, stdin);
        cin >> buff;
        //buff[strlen(buff) - 1] = 0;
        buff[strlen(buff)] = 0;
        sem_post(&sem2);

        if (strncmp(buff, "end", 3) == 0)
        {
            break;
        }
    }

    return 0;
}

条件变量

条件变量提供了一种线程间的通知机制:当某个共享数据达到某个值的时候,唤醒等待
这个共享数据的线程。

pthread_cond_init()

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);//初始化条件变量

//cond,指向要初始化的条件变量的指针

//attr,通常为NULL

pthread_cond_wait()

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);//在满足某个条件之前让线程进入等待状态

//cond,指向条件变量的指针

//mutex,指向互斥锁的指针

 pthread_cond_signal()

int pthread_cond_signal(pthread_cond_t *cond);//向等待在条件变量上的单个线程发送信号

//cond,指向条件变量的指针

 pthread_cond_broadcast()

int pthread_cond_broadcast(pthread_cond_t *cond); //向等待在条件变量上的所有线程发送信号

//cond,指向条件变量的指针

pthread_cond_destroy()

 int pthread_cond_destroy(pthread_cond_t *cond);//销毁条件变量

//cond,指向条件变量的指针

实践

使用条件变量和互斥锁使两个线程交替输出信息。

#include<iostream>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>

using namespace std;

pthread_mutex_t mutex;
pthread_cond_t cond;

void *fun1(void *arg)
{
    char *s = (char *)arg;
    while (1)
    {
        // 阻塞,被唤醒
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond, &mutex);
        pthread_mutex_unlock(&mutex);

        cout << "fun1 read:" << s << endl;

        if (strncmp(s, "end", 3) == 0)
        {
            break;
        }
    }

    return NULL;
}

void *fun2(void *arg)
{
    char *s = (char *)arg;
    while (1)
    {
        // 阻塞,被唤醒
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond, &mutex);
        pthread_mutex_unlock(&mutex);

        cout << "fun2 read:" << s << endl;

        if (strncmp(s, "end", 3) == 0)
        {
            break;
        }
    }

    return NULL;
}

int main()
{
    pthread_t id[2];
    char buff[128] = {0};

    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);
    pthread_create(&id[0], NULL, fun1, (void *)buff);
    pthread_create(&id[1], NULL, fun2, (void *)buff);

    while (1)
    {
        cin >> buff;
        if (strncmp(buff, "end", 3) == 0)
        {
            pthread_mutex_lock(&mutex);
            pthread_cond_broadcast(&cond);
            pthread_mutex_unlock(&mutex);

            break;
        }
        else
        {
            pthread_mutex_lock(&mutex);
            pthread_cond_signal(&cond);
            pthread_mutex_unlock(&mutex);
        }
    }

    pthread_join(id[0], NULL);
    pthread_join(id[1], NULL);

    pthread_cond_destroy(&cond);

    return 0;
}

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2023-12-05 21:26:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-05 21:26:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-05 21:26:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-05 21:26:03       20 阅读

热门阅读

  1. C++学习寄录(九.多态)

    2023-12-05 21:26:03       30 阅读
  2. 复杂sql分析 以及 索引合并

    2023-12-05 21:26:03       25 阅读
  3. bitnami Docker 安装ELK(elasticsearch, logstash, kibana)

    2023-12-05 21:26:03       35 阅读
  4. mysql多版本并发控制mvcc

    2023-12-05 21:26:03       30 阅读
  5. python代码块整行缩进与取消整行缩进快捷键

    2023-12-05 21:26:03       39 阅读
  6. 题目 异常处理

    2023-12-05 21:26:03       32 阅读
  7. day69

    day69

    2023-12-05 21:26:03      33 阅读
  8. 数据产品经理常用的ChatGPT通用提示词模板

    2023-12-05 21:26:03       37 阅读
  9. Ubuntu20.04 Kimera Semantic运行记录

    2023-12-05 21:26:03       42 阅读
  10. 机器学习之决策树及随机森林

    2023-12-05 21:26:03       37 阅读
  11. 修复 Ubuntu 2204 Wi-Fi 热点无法连接问题

    2023-12-05 21:26:03       43 阅读
  12. 决策树详解

    2023-12-05 21:26:03       30 阅读