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|进程间通信如何加锁

进程间通信有一种方式,大家有没有想过,这种通信方式中如何解决数据竞争问题?我们可能自然而然的就会想到用锁。但我们平时使用的锁都是用于解决线程间数据竞争问题,貌似没有看到过它用在进程中,那怎么办?

关于进程间的通信方式估计大多数人都知道,这也是常见的面试八股文之一。

个人认为这种面试题没什么意义,无非就是答几个关键词而已,更深入的可能面试官和面试者都不太了解岩凯销。

关于进程间通信方式我之前在【这篇文章】中有过介绍,感兴趣的可以移步去看哈。

进程间通信有一种方式,大家有没有想过,这种通信方式中如何解决数据竞争问题?

我们可能自然而然的就会想到用锁。但我们平时使用的锁都是用于解决线程间数据粗游竞争问题,貌似没有看到过它用在进程中,那怎么办?

我找到了两种方法,信号量和互斥锁。

直接给大家贴代码吧,首先是信号量方式:

代码中的MEOW_DEFER,它内部的函数会在生命周期结束后触发。它的核心函数其实就是下面这四个:

具体含义大家应该看孙禅名字就知道,这里的重点就是sem_init中的pshared参数,该参数为1表示可在进程间共享,为0表示只在进程内部共享。

第二种方式是使用锁,即pthread_mutex_t,可是pthread_mutex不是用作线程间数据竞争的吗,怎么能用在进程间呢?

可以给它配置一个属性,示例代码如下:

它的默认属性是进程内私有,但是如果给它配置成PTHREAD_PROCESS_SHARED,它就可以用在进程间通信中。

相关视频推荐

360度无死角讲解进程管理,调度器的5种实现

Linux进程间通信-信号量、消息队列和共享内存

学习视频教程-腾讯课堂

需要C/C++ Linux服务器架构师学习资料加qun获取(资料包括

C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg

等),免费分享

完整代码如下:

我想这两种方式应该可以满足我们日常开发过程中的大多数需求。

锁的方式介绍完之后,可能很多朋友自然就会想到原子变量,这块我也搜索了一下。但是也不太确定C++标准中的atomic是否在进程间通信中有作用,不过看样子boost中的atomic是可以用在进程间通信中的。

其实在研究这个问题的过程中,还找到了一些很多解决办法,包括:

Disabling Interrupts

Lock Variables

Strict Alternation

Peterson’s Solution

The TSL Instruction

Sleep and Wakeup

Semaphores

Mutexes

Monitors

Message Passing

Barriers

关于linux全局变量加锁的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。


数据运维技术 » Linux全局变量加锁,保证线程安全 (linux全局变量加锁)