Linux | Linux中的线程、互斥量、信号量的基本使用

Linux | Linux中的线程、互斥量、信号量的基本使用,第1张

Linux | Linux中的线程、互斥量、信号量的基本使用 前言

文章目录

前言一、概念

1.1、什么是线程1.2、实现原理1.3、线程共享资源1.4、线程非共享资源1.5、线程优缺点 二、线程常用方法

2.1、pthread_self2.2、pthread_create2.3、pthread_exit2.4、pthread_join2.5、pthread_detach2.6、pthread_cancel 三、线程同步

3.1、概念 四、互斥量

4.1、基本概念4.2、常用函数

4.2.1 pthread_mutex_init4.2.2 pthread_mutex_destroy4.2.3 pthread_mutex_lock4.2.3 pthread_mutex_unlock 4.3、读写锁

4.3.1 状态4.3.2 特性4.3.3 案例4.4 条件变量 五、信号量

5.1、sem_init5.2、sem_destroy5.3、sem_wait5.4、sem_post

一、概念

类Unix系统中,早期是没有“线程”概念的,80年代才引入,借助进程机制实现出了线程的概念。因此在这类系统中,进程和线程关系密切。

1.1、什么是线程

线程(LWP)是 *** 作系统能够进行运算调度的最小单位,是轻量级的进程,其本质仍是进程;

线程是轻量级的进程,则线程与它的区别有哪些?

与进程相比,线程没有独立的地址空间(共享);

在Linux下,线程是最小的执行单位;进程是最小分配资源的单元(一个线程的进程);

1.2、实现原理

进程与线程关系密切:

线程也有PCB,创建线程使用的底层函数和进程一样,都是clone;每个线程都有自己不同的PCB,但PCB中下指向内存资源的三级页表是相同的;进程可以蜕变成线程;线程可看做寄存器和栈的集合;

1.3、线程共享资源

文件描述符表;每种信号的处理方式;当前工作目录;用户ID和组ID;内存地址空间(.text/.data/.bss/heap/共享库);

1.4、线程非共享资源

线程ID;处理器线程和栈指针(内核栈);独立的栈空间(用户空间栈);errno变量;信号屏蔽字;

1.5、线程优缺点

优点:

提高程序并发性;开销小;数据通信、共享数据方便;

缺点:

库函数,不稳定;调试困难;对信号支持不友好;

二、线程常用方法 2.1、pthread_self
 

2.2、pthread_create
 

案例


#include 
#include 
#include 
using namespace std;

void *test_func(void *arg){

    cout << (int *)arg <<  "th I am 【" << pthread_self()  << "】thread" << endl;
    
    return nullptr;
}

int main(int argc, char* argv[])
{
    pthread_t tid;
    int ret, i;

    for(i=0; i < 5; ++i){
        if((ret = pthread_create(&tid, NULL, test_func, (void *)i)) != 0){
            cout << "pthread error" << endl;
            exit(1);
        }
    }
    pthread_exit(NULL);

}


2.3、pthread_exit
 

2.4、pthread_join
 

案例


#include 
#include 
#include 
using namespace std;

typedef struct {
    std::string name;
    int age;
}exit_t;

void *func(void *){
    exit_t *m_t = new exit_t;
    m_t->name = "xiaomi";
    m_t->age = 15;
    
    cout << "I am thread..." << endl;

    pthread_exit((void *)m_t);
}


int main(int argc, char* argv[])
{
    pthread_t tid;
    exit_t *m_t;
    int ret;

    cout << "I am main..." << endl;
    if((ret = pthread_create(&tid, NULL, func, NULL)) != 0){
        cout << "create error" << endl;
        exit(1);
    }

    pthread_join(tid, (void **)&m_t);
    cout << "name: 【" << m_t->name
        << "】" << " age:【"
        << m_t->age << "】" << endl;
    pthread_exit((void *)1);
    

    return 0;
}
 	


2.5、pthread_detach
 

案例


#include 
#include 

using namespace std;

void *func(void *arg){
    cout << "I am pthread" << endl;

    return (void *)1;
}



int main(int argc, char* argv[])
{
    pthread_t tid;

    pthread_create(&tid, NULL, func, NULL);

    cout << "I am main" << endl;

    int ret = pthread_detach(tid);
    cout << "detach pthread => " << ret << endl;

    return 0;
}


2.6、pthread_cancel
 

案例


#include 
#include 
#include 

using namespace std;


void *func(void *arg){
    while(1){
        cout << "---------------" << endl;
        sleep(1);
    }
    pthread_testcancel();
}

int main(int argc, char* argv[])
{
    pthread_t tid;

    pthread_create(&tid, NULL, func, NULL);

    cout << "I am main" << endl;
    sleep(3);
    pthread_cancel(tid);
    
    return 0;
}

三、线程同步 3.1、概念

指一个线程发出某一个功能时,在没有得到结果之前,该调不返回。同时其他线程为保证数据一致性,不能调用该功能;

用于多个控制流,共同 *** 作一个共享资源的情况;

数据混乱原因

资源共享;调度随机;线程间缺乏必要的同步机制;

四、互斥量 4.1、基本概念

每个线程在对资源 *** 作前都尝试先加锁,成功上锁才能 *** 作, *** 作结束后解锁,确保在于时间有关的 *** 作上不会出现错误;

4.2、常用函数 4.2.1 pthread_mutex_init
 
4.2.2 pthread_mutex_destroy 
 
4.2.3 pthread_mutex_lock 
 
4.2.3 pthread_mutex_unlock 
 

案例


#include 
#include 
#include 
using namespace std;

pthread_mutex_t mutex;


void *func(void *arg){

    while(1){
        pthread_mutex_lock(&mutex);
        cout << "I am pthread" << endl;
        sleep(1);
        pthread_mutex_unlock(&mutex);
        sleep(2);
    }
    return (void *)1;
}

int main(int argc, char* argv[])
{
    pthread_t tid;

    pthread_mutex_init(&mutex, NULL);
    pthread_create(&tid, NULL, func, NULL);

    while(1){
        pthread_mutex_lock(&mutex);
        cout << "I am main" << endl;
        sleep(1);
        pthread_mutex_unlock(&mutex);
        sleep(2);
    }

    pthread_join(tid, NULL);
    pthread_mutex_destroy(&mutex);

    return 0;
}

4.3、读写锁 4.3.1 状态

读模式下加锁状态;写模式下加锁状态;不加锁状态;

4.3.2 特性

写锁优先级别高;写独占,读共享;

4.3.3 案例

#include 
#include 
#include 
using namespace std;

int count;
pthread_rwlock_t rwlock;


void *r_func(void *arg){
    while(1){
        pthread_rwlock_wrlock(&rwlock);
        cout << "【read】 data = " << count << " thread_id: " << pthread_self() << endl;
        pthread_rwlock_unlock(&rwlock);
        sleep(1);
    }

    return nullptr;
}


void *w_func(void *arg){

    while(1){
        pthread_rwlock_wrlock(&rwlock);
        cout << "【write】  " << count++ << " thread_id: " << pthread_self() << endl;
        pthread_rwlock_unlock(&rwlock);
        sleep(1);
    }
    return nullptr;
}

int main(int argc, char* argv[])
{
    
    int i;
    pthread_t pid[8];

    pthread_rwlock_init(&rwlock, NULL);
    
    for(i=0; i<3; ++i)
        pthread_create(&pid[i], NULL, w_func, NULL);

    
    for(i=0; i<5; ++i)
        pthread_create(&pid[i+3], NULL, r_func, NULL);

    for(i=0; i<8; ++i){
        pthread_join(pid[i], NULL);
    }
    pthread_rwlock_destroy(&rwlock);

    return 0;
}

4.4 条件变量

本身不是锁,可造成线程阻塞。通常与互斥锁配合使用,给多线程提供一个会合场所;

pthread_cond_init

 

pthread_cond_destroy

 

pthread_cond_wait

 

pthread_cond_signal

 

pthread_cond_broadcast

 

案例


#include 
#include 
#include 
#include 
using namespace std;


vector vc;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;; 


void *product_func(void *arg){
    
    while(1){
        pthread_mutex_lock(&mutex);
        vc.push_back(rand() % 100);
        cout << "product 【" << vc[0] << "】" << endl;
        pthread_mutex_unlock(&mutex);

        pthread_cond_signal(&has_product);

        sleep(2);
    }
    return NULL;
}


void *comsump_func(void *arg){
    
    while(1){
        pthread_mutex_lock(&mutex);
        while(vc.empty()){
            pthread_cond_wait(&has_product, &mutex);
        }
        cout << "comsump 【" << vc[0] << "】" << endl;
        vc.pop_back();
        pthread_mutex_unlock(&mutex);
        sleep(2);
    }

    return NULL;
}

int main(int argc, char* argv[])
{
    pthread_t ptid, ctid;

    pthread_create(&ptid, NULL, product_func, NULL);
    pthread_create(&ctid, NULL, comsump_func, NULL);

    pthread_join(ptid, NULL);
    pthread_join(ctid, NULL);
    return 0;
}

五、信号量

相当于进化版的互斥锁,既能保证同步,数据不混乱,又能提高线程并发;

5.1、sem_init
 
5.2、sem_destroy 
 
5.3、sem_wait 
 
5.4、sem_post 
 

案例

#include 
#include 
#include 
#include 
using namespace std;


int queue[5];
sem_t blank_n, product_n;


void *product_func(void *arg){
    
    int i=0;
    while(1){
        sem_wait(&blank_n);
        queue[i%5] = rand() & 100;
        cout << "produce " << queue[i%5] << endl;
        sem_post(&product_n);

        i++;
        sleep(2);
    }
    return NULL;
}


void *comsump_func(void *arg){
    
    int i=0;
    while(1){
        sem_wait(&product_n);
        cout << "consume " << queue[i%5] << endl;
        queue[i%5] = 0;
        sem_post(&blank_n);

        i++;
        sleep(2);
    }

    return NULL;
}

int main(int argc, char* argv[])
{
    pthread_t ptid, ctid;
    sem_init(&blank_n, 0, 5);
    sem_init(&product_n, 0, 0);

    pthread_create(&ptid, NULL, product_func, NULL);
    pthread_create(&ctid, NULL, comsump_func, NULL);

    pthread_join(ptid, NULL);
    pthread_join(ctid, NULL);

    sem_destroy(&blank_n);
    sem_destroy(&product_n);


    return 0;
}


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5704455.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存