Linux - 线程特性举例

这里主要演示线程的以下几个特性
  • 线程共享同一地址空间(全局变量,堆,栈)
  • 线程退出引起进程退出
  • 多线程充分利用多核CPU资源

同组线程共用同一地址空间

  • 全局变量
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

//1.共享全局区资源
int g_count = 0;

void* ThreadEntry1(void* arg)
{
    (void)arg;
    while(1)
    {
        ++g_count;
        printf("t1 : %d\n",g_count);
        sleep(1);
    }
    return NULL;
}

void* ThreadEntry2(void* arg)
{
    (void)arg;
    while(1)
    {
        ++g_count;
        printf("t2 : %d\n",g_count);
        sleep(1);
    }
    return NULL;
}

int main()
{
    pthread_t t1,t2;
    pthread_create(&t1,NULL,ThreadEntry1,NULL);
    pthread_create(&t2,NULL,ThreadEntry2,NULL);
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);
    return 0;
}

上面代码中,有一个全局变量 g_count,两个线程,同时尝试去对 全局变量 g_count 进行修改
结果演示:

根据运行结果,我们可以看到,同组线程对全局变量是共享的

  • 堆上的变量
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

//2.共享堆上的资源
void* ThreadEntry1(void* arg)
{
    int* p = (int*)arg;
    while(1)
    {
        ++(*p);
        printf("t1 : %d\n",*p);
        sleep(1);
    }
    return NULL;
}

void* ThreadEntry2(void* arg)
{
    int* p = (int*)arg;
    while(1)
    {
        ++(*p);
        printf("t2 : %d\n",*p);
        sleep(1);
    }
    return NULL;
}

int main()
{
    int* p = (int*)malloc(sizeof(int));
    pthread_t t1,t2;
    pthread_create(&t1,NULL,ThreadEntry1,p);
    pthread_create(&t2,NULL,ThreadEntry2,p);
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);
    return 0;
}

上面代码中,在main函数中malloc出了一段空间,这段空间在堆上,线程1和2同时去修改这个堆上的变量。


  • 栈上的变量
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

//3.共享线程栈
//  使用栈上变量比较危险,我们使用前必须保证变量存在
//  但是主线程比较安全,因为他存在于整个进程
void* ThreadEntry1(void* arg)
{
    int* p = (int*)arg;
    while(1)
    {
        ++(*p);
        printf("t1 : %d\n",*p);
        sleep(1);
    }
    return NULL;
}

void* ThreadEntry2(void* arg)
{
    int* p = (int*)arg;
    while(1)
    {
        ++(*p);
        printf("t2 : %d\n",*p);
        sleep(1);
    }
    return NULL;
}

int main()
{
    int a = 0;
    int* p = &a;
    pthread_t t1,t2;
    pthread_create(&t1,NULL,ThreadEntry1,p);
    pthread_create(&t2,NULL,ThreadEntry2,p);
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);
    return 0;
}

代码中将主线程栈上一个变量a传给两个线程的线程入口函数,线程1和2分别随主线程栈上的元素进行改变。
注意:
修改栈上的资源是比较危险的,因为我们说过,每个线程都有自己的一个栈,这个但是这个栈是可以被访问也可以被改变的,试想,如果线程1已经退出了,线程2尝试去修改线程1栈上的元素,这是就很可能造成访问越界!但是,访问主线程栈上的元素相对比较安全,因为主线程栈是大家所共享的。




线程退出引起进程退出

线程组中某一个线程访存异常,都会导致进程异常终止。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

//解引用空指针
//会导致硬件设备MMU发现这是一个异常操作
//会给操作系统发送一个异常
//操作系统内核就会给进程发送11号信号,导致进程异常终止 - 段错误

//解引用空指针使线程异常终止,观察
//线程一旦异常终止,就会导致整个进程都结束掉
void* ThreadEntry1(void* arg)
{
    int* p = (int*)arg;
    while(1)
    {
        ++(*p);
        printf("t1 : %d\n",*p);
        int *ptr = NULL;
        *ptr = 10;
        sleep(1);
    }
    return NULL;
}

void* ThreadEntry2(void* arg)
{
    int* p = (int*)arg;
    while(1)
    {
        ++(*p);
        printf("t2 : %d\n",*p);
        sleep(1);
    }
    return NULL;
}

int main()
{
    int a = 0;
    int* p = &a;
    pthread_t t1,t2;
    pthread_create(&t1,NULL,ThreadEntry1,p);
    pthread_create(&t2,NULL,ThreadEntry2,p);
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);
    return 0;
}

线程尝试对空指针解引用时,进程终止。


多线程充分利用多核CPU资源

  • 场景1,创建对个线程不停歇工作,使用top指令查看CPU利用率
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

//利用top指令查看cpu占用率
void* ThreadEntry(void* arg)
{
    (void)arg;
    while(1)
    {}
    return NULL;
}

int main()
{
    pthread_t tid[32];
    int n = 4;
    int i = 0;
    for(; i < n; ++i)
    {
        pthread_create(&tid[i],NULL,ThreadEntry,NULL);
    }
    for(i = 0; i < n; ++i)
    {
        pthread_join(tid[i],NULL);
    }
    return 0;
}

创建两个线程,这两个线程一直在死循环(可换成具体场景)。

如上图观察,CPU占用率可高达400%(四核CPU),证明我们充分利用了CPU资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值