专注Java教育14年 全国咨询/投诉热线:444-1124-454
赢咖4LOGO图
始于2009,口口相传的Java黄埔军校
首页 hot资讯 多线程同步的例子

多线程同步的例子

更新时间:2021-10-09 10:45:11 来源:赢咖4 浏览962次

线程是一个执行单元,由其程序计数器、堆栈和一组寄存器组成。人们总是混淆线程和进程,区别很简单,进程提供执行程序所需的资源,而线程是进程内可以调度执行的实体。线程比进程有很多优点,主要的优点是,线程通过并行改进应用程序。我们将利用这个并行概念来编写一个简单的 C 并理解为什么我们需要线程同步。

让我们编写一个具有单线程的简单 C 程序。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
volatile long int a = 0;
int main()
{
    int i;
    a = 0;
    for(i = 0; i < 100000; i++)
    {
        a = a + i;
    }
    printf("%ld\n",a);
    return 0;
}

上面的代码很简单,它是单线程的,不用担心并行性。当我们执行并运行上面的代码时,我们每次都会得到4999950000。该代码具有三个主要的机器代码指令。

LDR R0, a              
ADD R0, R0, R1
STR R0, a

现在让我们稍微修改一下多线程的代码,看看它的行为。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
volatile long int a = 0;
pthread_mutex_t aLock;
void threadFunc()
{
    int i;
    for (i = 1; i < 200000 ; i++)
    {
        a = a + 1;
    }
}
void threadFunc2()
{
    int i;
    for(i = 200000; i <= 500000; i++)
    {
        a = a + i;
    }
}
int main()
{
    pthread_t th_one, th_two; 
    int i;
    a = 0;
    pthread_create(&th_one, NULL, (void*)&threadFunc, NULL);  // Create a new thread for threadFunc
    pthread_create(&th_two, NULL, (void*)&threadFunc2, NULL); // Create a new thread for threadFunc2
    pthread_join(th_one, NULL);  // waiting to join thread "th_one" without status
    pthread_join(th_two, NULL);  // waiting to join thread "th_two" without status
    printf("%ld\n",a);
    return 0;
}

我们创建了两个新线程threadFunc和threadFunc2。让我们用命令编译上面的代码

$ gcc -pthread m_thread.c -o m_thread

当我们多次运行二进制 m_thread 时,我们会看到类似这样的内容

令我们惊讶的是,输出是不确定的。那么,造成这种奇怪现象的原因可能是什么?为什么我的电脑会这样?答案是,我们没有处理线程同步。让我们了解为什么会发生这种情况。

在 SC1 中,'a' 被加载到 th1 的本地内存中,然后它执行操作并存储回主内存。类似地,在 SC2 中,'a' 被加载到 th2 的本地内存中,并在操作后存储回主内存。现在,在 SC3 'a' 由 th1 和 th2 获取,因为没有线程同步,因此我们可以看到 th1 存储的值丢失了,操作后基本上由 th2 更新。这是我为我们的理解添加的一个结果。然而,每次我们朗姆酒二进制可执行文件时,后台都会发生许多这样的后果,导致不同的输出。

现在,我们如何实现进程同步?一种方法是使用互斥锁。请参阅下面的修改示例。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
volatile long int a = 0;
pthread_mutex_t aLock;
void threadFunc(void* arg)
{
    int i;
    for (i = 1; i < 200000 ; i++)
    {
        pthread_mutex_lock(&aLock); // Lock a mutex for a
        a = a + 1;
        pthread_mutex_unlock(&aLock); // Unlock a mutex for a
    }
}
void threadFunc2(void *arg)
{
    int i;
    for(i = 200000; i <= 500000; i++)
    {
        pthread_mutex_lock(&aLock); // Lock a Mutex for a
        a = a + i;
        pthread_mutex_unlock(&aLock); // Unlock a mutex for a
    }
}
int main()
{
    pthread_t th_one, th_two; 
    int i;
    a = 0;
    pthread_create(&th_one, NULL, (void*)&threadFunc, NULL);  // Create a new thread for threadFunc
    pthread_create(&th_two, NULL, (void*)&threadFunc2, NULL); // Create a new thread for threadFunc2
    pthread_join(th_one, NULL);  // waiting to join thread "one" without status
    pthread_join(th_two, NULL);  // waiting to join thread "two" without status
    printf("%ld\n",a);
    return 0;

当我们执行上述二进制文件时,我们每次运行都会得到相同的输出。

在这种方法中,在代码的入口部分,在临界区内修改和使用的关键资源上获取一个 LOCK,并在退出部分释放 LOCK。由于资源在进程执行其临界区时被锁定,因此其他进程无法访问它。

以上就是多线程同步的例子,大家若想了解更多相关信息,可以关注一下赢咖4的Java多线程编程教程,里面有更详细的知识可以学习,希望对大家能够有所帮助。

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>