【Linux】线程同步

linux线程同步 Linux线程线程框架一、线程概念**线程的概念**:线程和进程的区别:二、线程共享资源和非共享资源线程共享资源:线程非共享资源:三、线程的优缺点优点:缺点:四、线程控制函数获取线程ID pthread_self创建线程pthread_create线程退出函数pthread_exit线程回收pthread_join线程分离pthread_detach杀死进程pthread_cancelpthread_equal五、线程属性梗概线程属性初始化设置属性分离态线程使用注意事项线程同步框架一、线程同步的一些概念1. 阅读详情

线程同步

线程仅仅互斥,是可以保证线程安全的。但是,这不合理!如果一个线程竞争到了锁,那么再它释放后它依然可以竞争个锁。因为CPU此时正在执行当前线程,所以该线程又可以继续竞争锁。 这样就会造成一个问题,有5个线程抢10000张票,可是线程1就抢了9000张,线程2抢了1000张。这就会造成其他另外三个线程一直申请锁却申请不到的情况。这个问题也被称为饥饿问题。

举个例子:

一个自习室只有一把钥匙,而每次这个自习室只能待一个人,且这个人持有钥匙。有一天你凌晨2点就起来去抢自习室,你抢到了并把自习室钥匙放口袋里进去自习,这时外面逐渐有人来自习,但是他们没有这个自习室的钥匙。所以他们只能在外面等待,这时你突然想出去吃个饭,上个厕所。那么你带着钥匙出去,并在外面把门反锁。这种行为就是线程持有锁挂起了。 而不久后你回到自习室,不太想学了,所以你就走到门口,把钥匙挂到墙上。可是你突然转念一想 : “算了,还是再学会吧。”。因为此时你离这个钥匙最近,所以你竞争的能力非常强。你就又拿到钥匙,进去自习了一份,你又想走了。于是又来到门口把钥匙挂门口隔壁的墙上,然后刚挂上去,你又想继续学了。又把钥匙拿下来继续进去学习… 如此反复。就造成了门外等待自习室的人的饥饿问题。而当你学完时真正准备走时,你把钥匙挂墙上后。结果外面的人争先恐后,毫无秩序的冲过来抢夺钥匙。

这里的你和外面自习室的人都是一个个线程,而钥匙就是这把锁,自习室就是临界资源。只有持有锁才能访问临界资源。可是因为锁刚从你当前的线程中释放,那么竞争锁能力最强的也是你当前的线程。 那么这样就很容易会造成其他线程的饥饿问题。 但是这个线程它有错吗??? 它没错!但是这不合理!!

那么怎么让这合理起来呢?

要合理起来,那么就让释放锁的线程,跑到最后面去排队。 还是上面那个例子,一旦你把钥匙挂墙上。那么你就必须老老实实到后面排队。这样可以确保一定的顺序时,但是还会面临一个问题。 有人插队怎么办???

从线程的角度来说,线程A已经把锁释放了。随后线程A跑到了最后的位置等待调度。这样可以保证一定的顺序的问题。接下来CPU准备调度线程B了,可是线程C它想配合,直接插队到了线程B前面。所以CPU就先调度线程C了。

CPU,线程A,B,C,它们有错吗? CPU只负责调度,谁来了调度谁,CPU没错。A,B,C线程都在尽心尽力的竞争锁。因为锁本来就是临界资源,它们也没错。但是,这不合理!!

于是就有了条件变量,可以保证线程同步。

条件变量

条件变量如何保证线程同步呢?还是自习室的例子,当你在自习室。外面等待的人都在睡觉(线程挂起),当你要走了挂回钥匙时(释放锁),外面的人就全部醒过来(线程唤醒)竞争锁。那么我们不要让他们全部醒过来,那么我们加一个管理员,让管理员每次只喊醒队伍最前面的那个,然后再让刚刚退出自习室的人到最后面去排队。 这样依次下去,是不是就能保证一定的顺序性了?

同步的情况下,想要每个线程先竞争锁 -> 竞争锁后检测是否满足访问临界资源的条件 -> 满足则访问 -> 不满足就在条件变量下等待 -> 等待之前释放锁 -> 唤醒回来重新获得锁 -> 访问临界资源

而让线程等待和唤醒线程。我们都需要用到条件变量。

条件变量和锁一样是一个变量,我们可以用条件变量让线程在该条件变量下等待。然后让主线程去唤醒条件变量。

条件变量相关函数:

pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //如果条件变量是全局的,可以这样初始化

//初始化全局变量,第一个参数是条件变量的地址,第二参数是条件变量的属性
int pthread_cond_init(pthread_cond_t *restrict cond,
                      const pthread_condattr_t *restrict attr);

//销毁条件变量,传条件变量地址
int pthread_cond_destroy(pthread_cond_t *cond);

//在条件变量下等待,第一个参数是条件变量地址,第二个参数是锁的地址,第三个参数是要等待的时间
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
              pthread_mutex_t *restrict mutex,
              const struct timespec *restrict abstime);

//在条件变量下等待,第一个参数是要等待的条件变量地址,第二个参数是锁
int pthread_cond_wait(pthread_cond_t *restrict cond,
              pthread_mutex_t *restrict mutex);

//依次唤醒所有在条件变量下等待的线程
int pthread_cond_broadcast(pthread_cond_t *cond);

//唤醒单个在条件变量下等待的线程
int pthread_cond_signal(pthread_cond_t *cond);

代码测试:

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

#define TNUM 4

typedef void (*func_t)(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond);

int tickets = 5;
bool flag = true;

class ThreadData
{
public:
    ThreadData(const std::string &name, func_t func, pthread_mutex_t *mutex, pthread_cond_t *cond) : _name(name), _func(func), _mutex(mutex), _cond(cond) {}

public:
    std::string _name;
    func_t _func;
    pthread_mutex_t *_mutex;
    pthread_cond_t *_cond;
};

void func1(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    while (flag)
    {
        pthread_mutex_lock(mutex);
        pthread_cond_wait(cond, mutex);  //在条件变量下等待
        std::cout<< name  << " runing ....下载" << std::endl; 
        pthread_mutex_unlock(mutex);
    }
}
void func2(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    while (flag)
    {
        pthread_mutex_lock(mutex);
        pthread_cond_wait(cond, mutex);  //在条件变量下等待
        std::cout<< name  << " runing ....查看用户" << std::endl; 
        pthread_mutex_unlock(mutex);
    }
}
void func3(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    while (flag)
    {
        pthread_mutex_lock(mutex);
        pthread_cond_wait(cond, mutex);  //在条件变量下等待
        std::cout<< name  << " runing ....扫描" << std::endl; 
        pthread_mutex_unlock(mutex);
    }
}
void func4(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    while (flag)
    {
        pthread_mutex_lock(mutex);
        pthread_cond_wait(cond, mutex); //在条件变量下等待
        std::cout<< name  << " runing ....广播" << std::endl; 
        pthread_mutex_unlock(mutex);
    }
}

void *Entry(void *args)
{
    ThreadData *td = (ThreadData *)args;
    td->_func(td->_name, td->_mutex, td->_cond); //调用线程绑定的函数
    delete td;
    return nullptr;
}

int main()
{
    pthread_mutex_t mtx; // 互斥锁
    pthread_cond_t cond; // 条件变量

    pthread_mutex_init(&mtx, nullptr);
    pthread_cond_init(&cond, nullptr);

    func_t funs[4] = {func1, func2, func3, func4}; //函数指针数组,存储上面4个函数
    pthread_t tids[4];

    // 创建线程
    for (int i = 0; i < TNUM; i++)
    {
        std::string name = "thread ";
        name += std::to_string(i + 1);
        ThreadData *td = new ThreadData(name, funs[i], &mtx, &cond); //创建线程数据对象,存储线程的数据以及锁,条件变量信息
        pthread_create(tids + i, nullptr, Entry, (void *)td);
    }
    sleep(5);
    int cnt = 10;
    while (cnt)
    {
        //每隔一秒唤醒一个线程
        std::cout << "wakeup thread ......  " << cnt--  << std::endl; 
        pthread_cond_signal(&cond); //唤醒一个线程
        sleep(1);
    }   
    std::cout << "ctrl done" << std::endl;
    flag = false; //结束线程内的循环
    //走到这里,所有线程依旧处于wait状态,在这里需要再唤醒一次
    pthread_cond_broadcast(&cond); //唤醒所有线程
    
    for (int i = 0; i < TNUM; i++)
    {
        pthread_join(tids[i], nullptr);
        std::cout << "thread " << i + 1 << "   quit....." << std::endl;
    }

    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);

    return 0;
}

这个代码的逻辑是1个主线程负责唤醒条件变量下等待的线程。其他四个线程负责输出一条打印语句,然后进入等待。

运行结果:

在这里插入图片描述

我们可以发现明显的顺序性,但第一次的顺序是无法确定的。因为CPU先调度的线程会先等待,先等待的会被先唤醒。但是后面的次序都和第一次的次序一样。这就保证了线程的同步。

注意!!!

pthread_cond_wait 必须在加锁和解锁之间等待!!因为pthread_cond_wait函数会让线程在等待之前释放锁,其而让其他线程进入临界资源。等到被唤醒时,又会重新获取锁。这也就是为什么 要在加锁和解锁之间wait。如果不在加锁和解锁之间wait,那么在最后想要在唤醒所有线程的时候就会产生死锁!!因为pthread_cond_wait的第二个参数就是一把锁,wait后会释放锁,被唤醒后重新获得锁。所以当最后一次唤醒时,被唤醒的线程就持有锁结束了。而其他线程就会在条件变量下等待锁,但是持有锁的线程已经释放了。所以就产生了死锁。

错误代码代表:

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

#define TNUM 2

typedef void (*func_t)(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond);

int tickets = 5;
bool flag = true;

class ThreadData
{
public:
    ThreadData(const std::string &name, func_t func, pthread_mutex_t *mutex, pthread_cond_t *cond) : _name(name), _func(func), _mutex(mutex), _cond(cond) {}

public:
    std::string _name;
    func_t _func;
    pthread_mutex_t *_mutex;
    pthread_cond_t *_cond;
};

void func1(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    while (flag)
    {
        //wait不加锁
        pthread_cond_wait(cond, mutex);  //在条件变量下等待
        std::cout<< name  << " runing ....下载" << std::endl; 
    }
}
void func2(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    while (flag)
    {
        //wait不加锁
        pthread_cond_wait(cond, mutex);  //在条件变量下等待
        std::cout<< name  << " runing ....查看用户" << std::endl; 
    }
}

void *Entry(void *args)
{
    ThreadData *td = (ThreadData *)args;
    td->_func(td->_name, td->_mutex, td->_cond); //调用线程绑定的函数
    delete td;
    return nullptr;
}

int main()
{
    pthread_mutex_t mtx; // 互斥锁
    pthread_cond_t cond; // 条件变量

    pthread_mutex_init(&mtx, nullptr);
    pthread_cond_init(&cond, nullptr);

    pthread_t tids[TNUM];
    func_t funs[TNUM] = {func1,func2};

    // 创建线程
    for (int i = 0; i < TNUM; i++)
    {
        std::string name = "thread ";
        name += std::to_string(i + 1);
        ThreadData *td = new ThreadData(name, funs[i], &mtx, &cond); //创建线程数据对象,存储线程的数据以及锁,条件变量信息
        pthread_create(tids + i, nullptr, Entry, (void *)td);
    }
    sleep(5);
    int cnt = 10;
    while (cnt)
    {
        //每隔一秒唤醒一个线程
        std::cout << "wakeup thread ......  " << cnt--  << std::endl; 
        pthread_cond_signal(&cond); //唤醒一个线程
        sleep(1);
    }   
    std::cout << "ctrl done" << std::endl;
    flag = false; //结束线程内的循环
    //走到这里,所有线程依旧处于wait状态,在这里需要再唤醒一次
    pthread_cond_broadcast(&cond); //唤醒所有线程
    // pthread_cond_signal(&cond); //唤醒一个线程
    //pthread_cond_signal(&cond); //唤醒一个线程
    
    std::cout << "--------------------------" << std::endl;
    for (int i = 0; i < TNUM; i++)
    {
        pthread_join(tids[i], nullptr);
        std::cout << "thread " << i + 1 << "   quit....." << std::endl;
    }

    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);

    return 0;
}

最后的运行结果就是10秒后最后一次唤醒时,线程1持有锁结束了。而线程2还在等待锁被唤醒,所以就变成了死锁。这时候就无法跳出来了。

在这里插入图片描述

而在循环内之所可以那是因为在singal之后。wait又重新获得了锁,然后经过了一次循环又来到wait,wait等待前会先释放锁。所以这时候其他线程又可以争夺锁,但是在最后一次的时候,线程1singal后不再wait。那么也就是在前一次wait之后获得了锁,随后线程结束时还持有锁,而线程2还在等待锁被唤醒。

而在线程结束前释放锁,又可以正常结束了:

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

#define TNUM 2

typedef void (*func_t)(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond);

int tickets = 5;
bool flag = true;

class ThreadData
{
public:
    ThreadData(const std::string &name, func_t func, pthread_mutex_t *mutex, pthread_cond_t *cond) : _name(name), _func(func), _mutex(mutex), _cond(cond) {}

public:
    std::string _name;
    func_t _func;
    pthread_mutex_t *_mutex;
    pthread_cond_t *_cond;
};

void func1(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    while (flag)
    {
        pthread_cond_wait(cond, mutex);  //在条件变量下等待
        std::cout<< name  << " runing ....下载" << std::endl; 
        pthread_mutex_unlock(mutex); //临走前释放锁
    }
}
void func2(const std::string &name, pthread_mutex_t *mutex, pthread_cond_t *cond)
{
    while (flag)
    {
        pthread_cond_wait(cond, mutex);  //在条件变量下等待
        std::cout<< name  << " runing ....查看用户" << std::endl; 
        pthread_mutex_unlock(mutex);//临走前释放锁

    }
}

void *Entry(void *args)
{
    ThreadData *td = (ThreadData *)args;
    td->_func(td->_name, td->_mutex, td->_cond); //调用线程绑定的函数
    delete td;
    return nullptr;
}

int main()
{
    pthread_mutex_t mtx; // 互斥锁
    pthread_cond_t cond; // 条件变量

    pthread_mutex_init(&mtx, nullptr);
    pthread_cond_init(&cond, nullptr);

    pthread_t tids[TNUM];
    func_t funs[TNUM] = {func1,func2};

    // 创建线程
    for (int i = 0; i < TNUM; i++)
    {
        std::string name = "thread ";
        name += std::to_string(i + 1);
        ThreadData *td = new ThreadData(name, funs[i], &mtx, &cond); //创建线程数据对象,存储线程的数据以及锁,条件变量信息
        pthread_create(tids + i, nullptr, Entry, (void *)td);
    }
    sleep(5);
    int cnt = 10;
    while (cnt)
    {
        //每隔一秒唤醒一个线程
        std::cout << "wakeup thread ......  " << cnt--  << std::endl; 
        pthread_cond_signal(&cond); //唤醒一个线程
        sleep(1);
    }   
    std::cout << "ctrl done" << std::endl;
    flag = false; //结束线程内的循环
    //走到这里,所有线程依旧处于wait状态,在这里需要再唤醒一次
    pthread_cond_broadcast(&cond); //唤醒所有线程
    //pthread_cond_signal(&cond); //唤醒一个线程
    //pthread_cond_signal(&cond); //唤醒一个线程
    
    std::cout << "--------------------------" << std::endl;
    for (int i = 0; i < TNUM; i++)
    {
        pthread_join(tids[i], nullptr);
        std::cout << "thread " << i + 1 << "   quit....." << std::endl;
    }

    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);

    return 0;
}

在这里插入图片描述

但是!!这是一种错误的写法!!请务必哪里有加锁,就哪里有解锁,wait在加锁和解锁之间完成。因为wait是对临界资源的条件检测,所以wait本身也应该在临界区之内。

MFC 修改CheckBox的文本颜色方法 设置主题 这一步是必须的,不可省略。 BOOL CMFCApplication1Dlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 // 设置主题 HWND 阅读详情

相关推荐

避开CPU瓶颈:手把手教你用RK3588的DMA-BUF实现V4L2到NPU的零拷贝数据流

本文详细介绍了如何在RK3588平台上利用DMA-BUF实现V4L2到NPU的零拷贝数据流,显著提升异构计算性能。通过实战指南展示了如何配置摄像头采集、RGA图像预处理和NPU推理优化,最终实现CPU占用率降低60%、延迟减少60%的效果,特别适合YOLOv5等AI推理应用的高效部署。

weixin_30374009的博客 571

Java线程饥饿

当连续不断拒绝线程访问资源并因此无法取得进展时,就会发生饥饿。当贪婪的线程长时间使用共享资源时,通常会发生这种情况。如果这种情况持续了很长时间,则线程没有获得足够的CPU时间或对资源的访问将无法取得足够的进展,从而导致线程不足。线程饥饿的可能原因之一是不同线程或线程组之间的线程优先级不正确。 另一个可能的原因可能是使用非终止循环(无限循环)或在特定资源上等待过多时间,同时保留了其他线程所需的关键锁。 通常建议尽量避免修改线程优先级,因为这是导致线程饥饿的主要原因。一旦开始使用线程优先级调整应用程序,它就

allway2的博客 3022

SAP 小结

关于SAP 开发的实习就要告一段落了,从刚开始接触,到现在已经6个月了,想要很简要的把自己对SAP的理解写出来,便于以后查阅(不定期更新)。 1. 什么是SAP? 广义的SAP,可以指代SAP公司以及SAP的各种产品,它的意义要在特定语境下才能确定。一般我们所说的SAP特指SAP ERP。 SAP ERP(enterprise resource planning)是一个企业信息系统。通过这个系

Remy的博客 1951

线程的死锁、活锁和饥饿现象

线程的活锁、死锁和饥饿现象

m0_62609939的博客 3038

解决vscode无法运行npm命令的问题(cmd可行)

Powershell以及vscode中npm命令使用不了

无痕坚守本心的博客 2749

LM Studio Bionic:本地AI智能体从部署到实战完整指南

AI智能体作为能够自主规划、执行多步任务的人工智能系统,其核心原理在于结合大语言模型的推理能力与工具调用机制。通过状态保持和任务分解算法,智能体实现了从单次问答到持续协作的技术跃迁。在工程实践中,这种架构显著降低了复杂任务自动化的门槛,特别适用于数据敏感场景和定制化需求。以Tesla V100等专业硬件为例,本地部署能充分发挥其大显存优势,支持更高精度的模型量化格式。在实际应用层面,智能体可无缝集成到代码审查、文档生成等开发工作流中,而LM Studio Bionic通过统一界面整合了模型服务、任务规划器等

weixin_29053695的博客 649

JavaEE 第7节 线程饥饿及其解决办法

线程饥饿)指的是多线程中,某些线程无法获得相关资源或者执行机会(阻塞,BLOCKED)长时间如此对线程的推进和响应造成明显影响的现象左边的蘑菇头和右边的小人都是线程,左边的蘑菇头因为在所中没有自己想要的资源所以从锁中出来,但是由于它的优先级比较高一从锁里出来,转头有跑进锁里面了,完全没有给右边的小进去的机会。当饥饿到一定程度,赋予线程的任务即使完成也不在具有实际意义的时候就说明这个线程被饿死了。

HYY的博客 1722

使用pytorch构建LSTM_AE模型的两种方式

2.基本LSTM_Unit计算——基本LSTM_AE结构 3.自定义LSTM_Unit计算——自定义LSTM_AE结构 1.LSTM-Encoder-Decoder模型结构及简要解析 图基本lstm计算单元

qq_37840762的博客 7273

线程死锁、锁死、饥饿、活锁讲解

死锁的产生原因以及规避方法等。

aaaPostcard的博客 2093

开源免费!ReaLTaiizor如何用MIT许可证打造专业级WinForm UI?

摘要: ReaLTaiizor是一款开源UI控件库,为WinForm应用提供现代化界面解决方案。支持100+组件、多主题切换(浅色/深色/自定义)和.NET 4.8-8.0全版本兼容,MIT许可证允许免费商用。通过NuGet快速安装,3步改造传统界面:1)注入主题(如this.Theme = new Dark()),2)替换原生控件为高颜值组件(如ModernGrid替代DataGridView),3)集成高级功能(分页/动画提示)。典型场景包括登录界面美化(进度动画+通知控件)和数据表格Material风

墨夶的博客 1520

直击高频编程考点:字符串知识及经典算法题总结

字符串相关基本练习题总结(最长公共子串、最长回文子串、最长无重复字符子串、最小覆盖子串、字符串相乘、中文数字表达转实际数字格式等)

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 172万+

15饥饿和公平

前一段时间工作有些忙碌,连续好几天,没有坚持写,甚是有些不舒坦。于是今天继续。上篇博文说到了死锁,不了解的小伙伴可以看一下上面两篇关于死锁方面的介绍。本篇博文主要是对饥饿和公平进行介绍。 如果一个线程因为CPU时间全部被其他线程抢走而得不到CPU运行时间,这种状态被称之为“饥饿”。而该线程被“饥饿致死”正是因为它得不到CPU运行时间的机会。解决饥饿的方案被称之为“公平性” – 即所有线程均能公平...

Burgess_Lee的博客 316

springboot整合sharding-jdbc实现分库分表详解

springboot整合sharding-jdbc实现分库分表详解

congge 9090

linux中实现线程同步的6种方法

linux线程同步的方法 下面是一个线程不安全的例子: #include<stdio.h> #include<pthread.h> int ticket_num=10000000; void *sell_ticket(void *arg) { while(ticket_num>0) { ticket_num--; } } int main() { pthread_t t1,t2,t3; pthread_create(&t1, NU

morris 4万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

【Linux】线程安全与线程同步

线程安全和死锁,以及线程同步的理解与示例

s_little_monster的博客 9432

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Linux——线程同步

本文介绍了多线程编程中同步与条件变量的核心概念及应用。首先通过抢票示例说明单纯互斥锁可能导致的线程饥饿问题,引入同步机制作为解决方案。同步在保证共享资源安全的基础上,通过条件变量实现线程执行顺序的合理调度。 条件变量包含等待队列和提示功能,关键接口包括初始化、销毁、等待(pthread_cond_wait)、单线程唤醒(pthread_cond_signal)和广播唤醒(pthread_cond_broadcast)。使用要点强调:1)线程必须在临界区内通过锁保护进入等待;2)可通过条件变量控制线程执行顺序

二哈的博客 1137

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Linux线程同步

线程同步

yuyuyuliang00的博客 842

Linux多线程——线程互斥与同步

摘要:多线程并发访问共享资源时存在数据竞争问题,需通过互斥锁和同步机制解决。 临界资源与竞争问题:多线程同时操作全局变量(如g_val--)时,由于CPU指令的非原子性,可能导致数据不一致。例如,线程切换时未完成的操作会使变量值异常。 互斥锁保护:通过pthread_mutex_t实现加锁(pthread_mutex_lock)和解锁(pthread_mutex_unlock),确保临界区代码的原子性。锁的粒度应尽量细以减少性能损失。 线程同步:条件变量(pthread_cond_t)解决线程间执行顺序问题

2401_83603768的博客 1455

[Linux]线程的互斥与同步

在多线程编程中,互斥与同步机制至关重要。互斥,是指同一时刻只允许一个线程访问共享资源,防止数据竞争。实现互斥常依赖互斥锁接口,通过加锁、解锁操作控制对资源的访问,其本质是线程获取和释放对共享资源的独占权。然而,若使用不当,可能产生死锁,即多个线程相互等待对方释放资源而陷入僵局。同步则着重于线程间的协作,按特定顺序访问资源。条件变量是同步的重要工具,通过其接口,线程可在条件满足时被唤醒,从而实现高效的线程协作,保障多线程程序的正确运行。

m0_74207969的博客 1578

Linux线程-互斥与同步

本章主要讲解学习Linux中对多线程的执行中的同步与互斥

~ 1623

【Linux】Linux线程互斥与同步

本文介绍了线程互斥与同步,互斥锁,条件变量,可重入与线程安全

qq_67582098的博客 2037

【Linux-多线程】线程同步

到午饭时间了,张三要去吃午饭,准备把钥匙挂在墙上,张三后面又想,等我再次过来的时候,我就要排到最后一个队伍了,正准备将钥匙挂在墙上,后面又拿回去,再进自习室学一会,在自习室里面又饿的不行,又把钥匙放回门口,后面又立马拿回来进自习室反反复复,张三由于饥饿,来回在自习室与门口挣扎,在自习室里也没有干什么,造成了时间浪费,也让后面的人着急。如果没有规则,那么会造成A同学不停的拿苹果,无论在与不在,B呢想放就放,不想放就一直不放,但是A确傻傻的一直去拿,浪费时间,占用资源效率低;在线程场景下,这种问题也不难理解。

2202_75331338的博客 2431

Linux: 线程同步

在上篇文章Linux : 多线程互斥-优快云博客我们讲解了线程互斥的概念,为了防止多个线程同时访问一份临界资源而出问题,我们引入了线程互斥,线程互斥其实就是多个线程同时争抢一份资源,谁抢到了就是谁的,抢不到的只能等待着下一次抢。虽然解决了多个线程同时访问同一资源所产生的问题,但是我们思考一下这样子合理吗?不合理,这会产生另一种问题——线程饥饿。

2301_79927432的博客 1192

Linux线程同步与互斥

上图中,线程1因为某些原因需要线程切换,进入等待队列。那么此时线程1需要把自己的上下文数据带走,其实就是把寄存器当中保存的值带走,并且没有对内存交换的0进行写回,也就是说此时内存中的mutex是0,那么线程2在交换mutex到寄存器当中,就会进行状态检测,此时检测到状态为0,说明当前已经有人占用锁了,则线程2进入到挂起状态,后来的线程依旧会如此,直到第一个线程执行完毕将锁释放。大部分情况,线程使用的数据都是局部变量,变量的地址空间在线程栈空间内,这种情况,变量归属单个线程,其他线程无法获得这种变量。

欢迎来到阿熊的blog~~ 1159
上一篇: 线程安全之锁的原理
下一篇: 并发编程之生产者消费者模型
林   子
博客等级 码龄4年 2671粉丝 64原创
评论 24
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林 子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值