共 1 篇文章

标签:Linux全局变量加锁,保证线程安全 (linux全局变量加锁)

Linux全局变量加锁,保证线程安全 (linux全局变量加锁)

在多线程程序中,保证资源的共享和访问安全是非常重要的。如果多个线程同时访问一个共享资源,很容易出现竞争条件(Race Condition)和数据冲突(Data Race)等问题,导致程序出现不可预料的行为。因此,在编写多线程程序时,需要采取一些措施来保证共享资源的访问安全。本文将介绍Linux系统中如何通过锁机制来保护全局变量,保证多个线程对变量的访问是安全的。 一、全局变量与线程安全 全局变量是指在整个程序执行期间都可见和访问的变量,它们通常定义在函数外部。全局变量既可以在单线程程序中使用,也可以在多线程程序中使用。不过,在多线程程序中,由于多个线程可以同时访问全局变量,会产生一些问题。 例如,假设有一个全局变量g_count,表示某个任务的计数器。如果在一个线程中使用g_count进行自增操作,那么另外一个线程也可能在同一时刻对g_count进行自增操作。由于自增操作包括读取原值和写入新值两个过程,多个线程同时进行自增操作就可能产生竞争条件,导致g_count的值出现错误。比如,线程1读取g_count的值为10,线程2也读取g_count的值为10,然后线程1对g_count的值加1得到11,紧接着线程2也对g_count的值加1得到11,此时g_count的值应该是12,但实际上却是11。 为了避免这样的问题,需要对全局变量进行加锁。多个线程在访问全局变量时,必须获得锁,然后才能对变量进行读写操作。这样可以保证任何时刻只有一个线程可以访问全局变量,从而避免竞争条件和数据冲突等问题。 二、Linux中的锁机制 Linux系统提供了多种锁机制,用来保护共享资源的访问安全。常用的锁机制包括:互斥锁、读写锁、自旋锁等。 互斥锁是一种最常用的锁机制。它可以保证同一时刻只有一个线程可以进入临界区,进入临界区的线程需要先获得互斥锁,执行完临界区的操作后释放互斥锁,其他线程才有机会进入临界区。互斥锁有两种状态:锁定和未锁定。当一个线程获得了互斥锁时,该锁处于锁定状态,其他线程需要等待该锁的释放才能进入临界区。当一个线程释放了互斥锁时,该锁变为未锁定状态,其他线程可以抢占该锁进入临界区。 读写锁是一种用于提高读操作并发性的锁机制。它可以有多个读者同时访问临界区,但只有一个写者可以访问临界区。当存在写者时,所有读者和其他写者都需要等待锁的释放。读写锁有两种状态:读锁和写锁。当一个线程获得了读锁时,它可以进行读操作但不能进行写操作;当一个线程获得了写锁时,它可以进行写操作但不能进行读操作。 自旋锁是一种非常轻量级的锁机制。它可以消除线程调度带来的性能开销,适用于高并发场景。自旋锁的锁定状态是通过忙等待实现的,即一个线程在获取锁时,如果发现锁已经被其他线程占用,就不断地循环检查锁的状态,直到锁被释放。这种机制可以避免线程的上下文切换,提高了程序的性能。 三、使用互斥锁保护全局变量 下面是一个示例程序,演示如何使用互斥锁保护全局变量,保证多线程对变量的访问安全。 “`c #include #include pthread_mutex_t g_mutex; // 全局互斥锁 int g_count = 0; // 全局计数器 void* thread_func(void* arg) // 线程处理函数 { int i; for (i = 0; i pthread_mutex_lock(&g_mutex); // 获得互斥锁 g_count++; // 对全局变量进行加1操作 pthread_mutex_unlock(&g_mutex); // 释放互斥锁 } return NULL; } int mn() { pthread_t tid1, tid2; // 线程ID pthread_mutex_init(&g_mutex, NULL); // 初始化互斥锁 pthread_create(&tid1, NULL, thread_func, NULL); // 创建线程1 pthread_create(&tid2, NULL, thread_func, NULL); // 创建线程2 pthread_join(tid1, NULL); // 等待线程1退出 pthread_join(tid2, NULL); // 等待线程2退出 pthread_mutex_destroy(&g_mutex); // 销毁互斥锁 printf(“g_count = %d\n”, g_count); // 输出全局计数器的值 return 0; } “` 在这个示例程序中,我们定义了一个全局互斥锁g_mutex和一个全局计数器g_count。线程处理函数thread_func会对g_count进行100000次加1操作,每次操作都会获得互斥锁并更新g_count,然后释放互斥锁。主函数中创建了两个线程来执行thread_func,执行完毕后输出g_count的值。 运行程序,可以看到输出的g_count值为202300,说明多线程对全局变量的访问是安全的。 四、 相关问题拓展阅读: linux|进程间通信如何加锁 linux|进程间通信如何加锁 进程间通信有一种方式,大家有没有想过,这种通信方式中如何解决数据竞争问题?我们可能自然而然的就会想到用锁。但我们平时使用的锁都是用于解决线程间数据竞争问题,貌似没有看到过它用在进程中,那怎么办? 关于进程间的通信方式估计大多数人都知道,这也是常见的面试八股文之一。 个人认为这种面试题没什么意义,无非就是答几个关键词而已,更深入的可能面试官和面试者都不太了解岩凯销。 关于进程间通信方式我之前在【这篇文章】中有过介绍,感兴趣的可以移步去看哈。 进程间通信有一种方式,大家有没有想过,这种通信方式中如何解决数据竞争问题? 我们可能自然而然的就会想到用锁。但我们平时使用的锁都是用于解决线程间数据粗游竞争问题,貌似没有看到过它用在进程中,那怎么办? 我找到了两种方法,信号量和互斥锁。 直接给大家贴代码吧,首先是信号量方式: 代码中的MEOW_DEFER,它内部的函数会在生命周期结束后触发。它的核心函数其实就是下面这四个: 具体含义大家应该看孙禅名字就知道,这里的重点就是sem_init中的pshared参数,该参数为1表示可在进程间共享,为0表示只在进程内部共享。 第二种方式是使用锁,即pthread_mutex_t,可是pthread_mutex不是用作线程间数据竞争的吗,怎么能用在进程间呢? 可以给它配置一个属性,示例代码如下: 它的默认属性是进程内私有,但是如果给它配置成PTHREAD_PROCESS_SHARED,它就可以用在进程间通信中。 相关视频推荐 360度无死角讲解进程管理,调度器的5种实现 Linux进程间通信-信号量、消息队列和共享内存...

技术分享