Linux线程互斥

Posted 种花家de小红帽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux线程互斥相关的知识,希望对你有一定的参考价值。

目录

C++11线程

C++线程封装

线程互斥

互斥锁

封装互斥锁


C++11线程

        C++11的多线程,本质是pthread库的封装

#include <iostream>
#include <thread>
#include <unistd.h>
using namespace std;

void thread_run() 
    while (1) 
        cout << "我是新线程..." << endl;
        sleep(1);
    


int main() 
    thread t1(thread_run);

    while (1) 
        cout << "我是主线程..." << endl;
        sleep(1);
    
    t1.join();
    return 0;

C++线程封装

        mythread.hpp

#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <pthread.h>
#include <cassert>
#include <cstdlib>

class Thread;

class Context 
public:
    Thread* _this;
    void* _args;
    Context() : _this(nullptr), _args(nullptr) 
    ~Context() 
;

class Thread 
    typedef std::function<void*(void*)> func_t;
public:
    Thread(func_t func, void* args, int number)
    : _func(func), _args(args) 
        char buffer[128];
        snprintf(buffer, sizeof(buffer), "thread-%d", number);
        _name = buffer;

        // start
        Context* ctx = new Context();
        ctx->_this = this;
        ctx->_args = _args;
        int n = pthread_create(&_tid, nullptr,start_routine, ctx);
        assert(n == 0);
    

    // 类内成员,有缺省参数
    // 在类内创建线程,想让线程执行对应的方法,需要将方法设置成static
    static void* start_routine(void* args) 
        Context* ctx = static_cast<Context*>(args);
        void* ret = ctx->_this->run(ctx->_args);
        delete ctx;
        return ret;

        // 静态方法不能调用成员方法或者成员变量
        // return _func(_args);
    

    void join() 
        int n = pthread_join(_tid, nullptr);
        assert(n == 0);
    

    void* run(void* args) 
        _func(args);
    

private:
    std::string _name;
    func_t _func;
    void* _args;
    pthread_t _tid;
;

        mythread.cc

#include "mythread.hpp"
#include <unistd.h>
#include <memory>

void* thread_run(void* args) 
    std::string work_type = static_cast<const char*>(args);
    while (true) 
        std::cout << "我是一个新线程, 我正在做: " << work_type << std::endl;
        sleep(1);
    


int main() 
    std::unique_ptr<Thread> thread1(new Thread(thread_run, (void*)"hello thread1. ", 1));
    std::unique_ptr<Thread> thread2(new Thread(thread_run, (void*)"hello thread2.. ", 2));
    std::unique_ptr<Thread> thread3(new Thread(thread_run, (void*)"hello thread3... ", 3));

    thread1->join();
    thread2->join();
    thread3->join();

    return 0;

线程互斥

        对变量进行++、--,在C、C++中一条语句,但在os中是至少三条指令:

                1. 从内存读取数据到cpu寄存器中

                2. 在寄存器对数据进行对应的算逻运算

                3. 写回新的结果到内存中变量的位置

        全局变量在没有保护的情况下,并不安全

        多个执行流进行安全访问的共享资源 ------ 临界资源

        多个执行流中访问临界资源的代码     ------ 临界区

        想让多个线程串行访问共享资源         ------ 互斥

        对一个资源进行访问的,要么不做,要么做完     ------- 原子性

#include "mythread.hpp"
#include <unistd.h>
#include <memory>

// 多个线程交叉执行的本质:让调度器尽可能频繁发生线程调度与切换
// 线程一般在什么时间发生切换呢?时间片到了,来了更高优先级的线程,线程等待的时候
// 线程检测一般是在什么时候呢?从内核态返回用户态的时候,线程要对调度状态进行检测,如果可以,就直接发送线程切换

// 共享资源, 火车票
int tickets = 10000;

void* thread_run(void* args) 
    std::string username = static_cast<const char*>(args);
    while (true) 
        // 假设票数为 1 时
        // 线程1将tickets=1写入寄存器中被切走
        // 此时线程2也将tickets=1写入寄存器被切走,线程3、线程4类似
        // 然后线程1进入if语句内,--tickets,线程2、线程3、线程4也依次 --tickets
        // 故结果出现负值
        if (tickets > 0) 
            usleep(1000);   // 单位为微妙, 1 秒 == 1000 毫秒 == 1000 000 微妙 == 1000 000 000 纳秒
            std::cout << username << " 正在抢票中: " << tickets << std::endl;
            --tickets;
        
        else 
            break;
        
    


int main() 
    std::unique_ptr<Thread> thread1(new Thread(thread_run, (void*)"user1", 1));
    std::unique_ptr<Thread> thread2(new Thread(thread_run, (void*)"user2", 2));
    std::unique_ptr<Thread> thread3(new Thread(thread_run, (void*)"user3", 3));
    std::unique_ptr<Thread> thread4(new Thread(thread_run, (void*)"user4", 4));

    thread1->join();
    thread2->join();
    thread3->join();
    thread4->join();

    return 0;

互斥锁

        锁本身就是一个共享资源,加锁的过程也是原子的

        锁申请成功,进入临界资源,其他线程阻塞等待

        锁申请成功,访问临界资源时别切走,其他线程不能申请锁,也便无法向后执行

        在使用锁的时候,保证粒度尽量小

        加锁是同步行为,对公共资源保护的时候要所有线程都加锁

创建互斥锁的方法多样,底层原理还是以下三个函数接口

#include "mythread.hpp"
#include <unistd.h>
#include <memory>
#include <vector>

#define NUM 4

// 多个线程交叉执行的本质:让调度器尽可能频繁发生线程调度与切换
// 线程一般在什么时间发生切换呢?时间片到了,来了更高优先级的线程,线程等待的时候
// 线程检测一般是在什么时候呢?从内核态返回用户态的时候,线程要对调度状态进行检测,如果可以,就直接发送线程切换

class ThreadData 
public:
    ThreadData(const std::string& threadname, pthread_mutex_t* pmutex)
    : _threadname(threadname), _pmutex(pmutex) ;
    ~ThreadData() ;

    std::string _threadname;
    pthread_mutex_t*_pmutex;
;

// 共享资源, 火车票
int tickets = 5000;

void* GetTicket(void* args) 
    // std::string username = static_cast<const char*>(args);
    ThreadData* td = static_cast<ThreadData*>(args);
    while (true) 
        // 加锁和解锁的过程是由多个线程串行执行,程序变慢
        // 锁只规定互斥访问,没有规定由谁优先执行
        // 锁就是真正的让多个执行流进行竞争的结果
        pthread_mutex_lock(td->_pmutex);
        // 上锁与解锁之间的代码就是临界区
        if (tickets > 0) 
            usleep(1000);   // 单位为微妙, 1 秒 == 1000 毫秒 == 1000 000 微妙 == 1000 000 000 纳秒
            std::cout << td->_threadname << " 正在抢票中: " << tickets << std::endl;
            --tickets;
            pthread_mutex_unlock(td->_pmutex);
        
        else 
            pthread_mutex_unlock(td->_pmutex);
            break;
        
        usleep(100);   //模拟形成一个订单给用户
    


int main() 
    // 初始化锁
    pthread_mutex_t lock;
    pthread_mutex_init(&lock, nullptr);

    std::vector<pthread_t> tids(NUM);
    for (int i = 0; i < NUM; ++i) 
        char buffer[64];
        snprintf(buffer, sizeof(buffer), "thread %d", i + 1);
        ThreadData* td = new ThreadData(buffer, &lock);
        pthread_create(&tids[i], nullptr, GetTicket, td);
    

    for (const auto& tid: tids) 
        pthread_join(tid, nullptr);
    

    // 释放锁
    pthread_mutex_destroy(&lock);

    return 0;

封装互斥锁

        当对象被构建的时候自动加锁,当对象被析构的时候解锁

        mymutex.hpp

#pragma once

#include <iostream>
#include <pthread.h>

class Mutex 
public:
    Mutex(pthread_mutex_t* plock = nullptr)
    : _plock(plock) ;

    void lock() 
        if (_plock) pthread_mutex_lock(_plock);
    

    void unlock() 
        if (_plock) pthread_mutex_unlock(_plock);
    

private:    
    pthread_mutex_t* _plock;
;

class LockGuard 
public:
    LockGuard(pthread_mutex_t* mutex)
    : _mutex(mutex) 
        _mutex.lock();  //在构造函数中进行加锁
    ;

    ~LockGuard() 
        _mutex.unlock();    //在析构函数中解锁
    

private:
    Mutex _mutex;
;

       

        mythread.cc

#include "mythread.hpp"
#include "mymutex.hpp"
#include <unistd.h>
#include <memory>
#include <vector>

#define NUM 4

// 多个线程交叉执行的本质:让调度器尽可能频繁发生线程调度与切换
// 线程一般在什么时间发生切换呢?时间片到了,来了更高优先级的线程,线程等待的时候
// 线程检测一般是在什么时候呢?从内核态返回用户态的时候,线程要对调度状态进行检测,如果可以,就直接发送线程切换

class ThreadData 
public:
    ThreadData(const std::string& threadname, pthread_mutex_t* pmutex)
    : _threadname(threadname), _pmutex(pmutex) ;
    ~ThreadData() ;

    std::string _threadname;
    pthread_mutex_t*_pmutex;
;

// 共享资源, 火车票
int tickets = 2000;

void* GetTicket(void* args) 
    // std::string username = static_cast<const char*>(args);
    ThreadData* td = static_cast<ThreadData*>(args);
    while (true) 
        // 设置代码块
        
        // 加锁和解锁的过程是由多个线程串行执行,程序变慢
        // 锁只规定互斥访问,没有规定由谁优先执行
        // 锁就是真正的让多个执行流进行竞争的结果
        // pthread_mutex_lock(td->_pmutex);
        LockGuard lock_guard(td->_pmutex);

            // 上锁与解锁之间的代码就是临界区
            if (tickets > 0) 
                usleep(1000);   // 单位为微妙, 1 秒 == 1000 毫秒 == 1000 000 微妙 == 1000 000 000 纳秒
                std::cout << td->_threadname << " 正在抢票中: " << tickets << std::endl;
                --tickets;
            //     pthread_mutex_unlock(td->_pmutex);
            
            else 
                // pthread_mutex_unlock(td->_pmutex);
                break;
            
        
        usleep(100);   //模拟形成一个订单给用户
    


int main() 
    // 初始化锁
    pthread_mutex_t lock;
    pthread_mutex_init(&lock, nullptr);

    std::vector<pthread_t> tids(NUM);
    for (int i = 0; i < NUM; ++i) 
        char buffer[64];
        snprintf(buffer, sizeof(buffer), "thread %d", i + 1);
        ThreadData* td = new ThreadData(buffer, &lock);
        pthread_create(&tids[i], nullptr, GetTicket, td);
    

    for (const auto& tid: tids) 
        pthread_join(tid, nullptr);
    

    // 释放锁
    pthread_mutex_destroy(&lock);

    return 0;

Linux学习_线程的互斥

线程的同步和互斥

同步和互斥的概念

  1. 线程同步
  • 线程同步是一个宏观的概念,在微观上包含线程的相互排斥(注意和线程互斥的不一样)和线程先后执行的约束问题
  • 解决同步方式
    • 条件变量
    • 线程信号量
  1. 线程互斥
  • 线程执行是相互排斥的,一个线程在操作共享资源时,其他线程是处于阻塞状态或等待状态,不可以操作共享资源。
  • 和线程同步相互排斥的区别是:线程互斥不考虑线程先后执行的约束问题。
  • 解决互斥方式
    • 互斥锁
    • 读写锁
    • 线程信号量

保证同一时间操作共享资源的线程只有一个。

  1. ATM线程冲突示例
    创建boy和girl线程同时对银行账户进行操作
    主函数:
typedef struct
{
	int code;
	double balance;
}Account,*pAccount;

//取款金额amt
extern double withdraw(pAccount a, double amt)
{
	if(amt<0 || amt> a->balance) return 0.0;
	double balance = a->balance;
	sleep(1);//模拟银行连接互联网取钱的延时
	balance -= amt;
	a->balance = balance;
	return amt; //成功则返回取款金额
}

//------------------------------------------------------------------------
/*
 * account_test.c
 * 创建boy和girl线程同时对银行账户进行操作
 */
//头文件
//--------------------------------
#include "account.h"
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
//--------------------------------

//结构体
//--------------------------------
typedef struct
{
	char name[20];
	pAccount account;
	double amt; //存取款金额
}OperArg;
//--------------------------------

//定义取款操作的线程运行函数
//--------------------------------
void* withdraw_fn(void* arg)
{
	OperArg *oa = (OperArg*)arg;
	double amt = withdraw(oa->account, oa->amt);
	
	printf("%8s(0x%lx) withdraw %f from account %d\\n",\\
	oa->name, pthread_self(), amt, oa->account->code);
	
	return (void*)0;
}
//--------------------------------

//定义存款操作的线程运行函数
//--------------------------------
void* deposit_fn(void* arg)
{
	OperArg *oa = (OperArg*)arg;
	double amt = deposit(oa->account, oa->amt);
	
	printf("%8s(0x%lx) deposit %f from account %d\\n",\\
	oa->name, pthread_self(), amt, oa->account->code);
	
	return (void*)0;
}
//--------------------------------

//定义检查银行账户的线程运行函数
//--------------------------------
void* check_fn(void* arg)
{
	return (void*)0;
}
//--------------------------------

//--------------------------------

//主函数
//--------------------------------
int main(void)
{
	int err;
	pthread_t boy, girl;
	pAccount a = create_account(100001, 10000);
	OperArg o1, o2; //o1,o2分别代表操作的两个用户
	
	strcpy(o1.name, "boy");
	o1.account = a;
	o1.amt = 10000;
	
	strcpy(o2.name, "girl");
	o2.account = a;
	o2.amt = 10000;
	
	//启动两个子线程(boy和girl)
	//同时操作同一个银行账户
	err = pthread_create(&boy, NULL,withdraw_fn, (void*)&o1);
	if(err != 0) perror("pthread create error");
	err = pthread_create(&girl, NULL,withdraw_fn, (void*)&o2);
	if(err != 0) perror("pthread create error");
	
	pthread_join(boy, NULL);
	pthread_join(girl, NULL);
	
	printf("account balance: %f\\n", get_balance(a));
	destroy_account(a);
	
	return 0;
}


输出:

girl(0xb657e460) withdraw 10000.000000 from account 100001
boy(0xb6d7f460) withdraw 10000.000000 from account 100001
account balance: 0.000000

男生女生同时取款,都取到了10000元,相当于两人一共取了20000,这是不对的。
此时线程不安全。
分析:boy girl 两者共同调用了withdraw函数,在栈中都有一个空间,girl在boy延时睡眠时进来,此时账户里余额并未改变,于是两人得到的balance都为10000。

线程互斥——互斥锁(互斥量)

  1. 概念:
  • 互斥锁(mutex)是一种简单的加锁的方法来控制对共享资源的访问。在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程能够对共享资源进行访问。若其他线程希望上锁一个已经被上了互斥锁的资源,则线程挂起,直到上锁的线程释放互斥锁为止。
  1. 互斥锁数据类型
  • pthread_mutex_t
  1. 互斥锁的创建和销毁
#include <pthread.h>
int pthread_mutex_init(
								pthread_mutex_t* restrict mutex,
								const pthread_mutexattr_t* mutexattr);

int pthread_mutex_destroy(pthread_mutex_t* mutex);
  • 返回:成功返回0,否则返回错误编号。
  • 参数:
    • mutex:互斥锁
    • mutexattr:互斥锁创建方式(一般写NULL,默认互斥锁类型)
      • PTHREAD_MUTEX_INITIALIZER:创建快速互斥锁
      • PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP:创建递归互斥锁
      • PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP:创建检错互斥锁
  1. 互斥锁上锁和解锁
#include <pthread.h>

int pthread_mutex_lock(pthread_mutex_t* mutex);
功能:上锁,拿不到锁则阻塞

int pthread_mutex_trylock(pthread_mutex_t* mutex);
功能:上锁,拿不到锁则返回出错信息

int pthread_mutex_unlock(pthread_mutex_t* mutex);
功能:释放锁

返回:成功返回0,否则返回错误编号。

对ATM示例进行加锁

/*account.c
*/
typedef struct
{
	int code;
	double balance;
	//定义一把互斥锁,用来对多个线程操作的银行账户(共享资源)进行加锁(保护)
	//建议一把互斥锁绑定一个账户,尽量不设置成全局变量,否则可能出现一把锁去锁几百个银行账户导致并发性降低
	pthread_mutex_t mutex;
}Account,*pAccount;

#include "account.h"
#include <malloc.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>


//创建账户
extern pAccount create_account(int code, double balance)
{
	pAccount a = (pAccount)malloc(sizeof(Account));
	assert(a != NULL);
	a->code = code;
	a->balance = balance;
	//对互斥锁进行初始化
	pthread_mutex_init(&a->mutex, NULL);
	return a;
}

//销毁账户
extern void destroy_account(pAccount a)
{
	assert(a != NULL);
	//销毁互斥锁
	pthread_mutex_destroy(&a->mutex);
	free(a);
}

//取款金额amt
extern double withdraw(pAccount a, double amt)
{
	assert(a != NULL);
	//以下对共享资源从上锁到释放的代码区称为
	//对共享资源操作的临界区,犹如一个禁区
	
	//对共享资源(账户)加锁
	pthread_mutex_lock(&a->mutex);
	
	if(amt<0 || amt> a->balance) 
	{
		//释放互斥锁
		pthread_mutex_unlock(&a->mutex);
		return 0.0;
	}
	double balance = a->balance;
	sleep(1);//模拟银行连接互联网取钱的延时
	balance -= amt;
	a->balance = balance;
	
	//释放互斥锁
	pthread_mutex_unlock(&a->mutex);
	
	return amt; //成功则返回取款金额
}

//存款
extern double deposit(pAccount a, double amt)
{
	assert(a != NULL);
	
	//对共享资源(账户)加锁
	pthread_mutex_lock(&a->mutex);
	
	if(amt<0){
		//释放互斥锁
		pthread_mutex_unlock(&a->mutex);
		return 0.0;
	}
	double balance = a->balance;
	sleep(1);
	balance += amt;
	a->balance = balance;
	
	//释放互斥锁
	pthread_mutex_unlock(&a->mutex);
	return amt;
}

//查看账户余额
extern double get_balance(pAccount a)
{
	assert(a != NULL);
	//对共享资源(账户)加锁
	pthread_mutex_lock(&a->mutex);
	double balance = a->balance;
	//释放互斥锁
	pthread_mutex_unlock(&a->mutex);
	return balance;
}

给每个线程加上锁,再运行主函数
输出:

 boy(0xb6dc5460) withdraw 10000.000000 from account 100001
 girl(0xb65c4460) withdraw 0.000000 from account 100001
account balance: 0.000000

  1. 互斥锁属性创建和销毁
#include <pthread.h>
int pthread_mutexattr_init(pthread_mutexattr_t* attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t* attr);
  • 返回:成功返回0,否则返回错误编号
  • 参数:attr:互斥锁属性
  1. 互斥锁进程共享属性操作
#include <pthread.h>

int pthread_mutexattr_getpshared(
										const pthread_mutexattr_t* restrict attr,
										int* restrict pshared);
										
int pthread_mutexattr_setpshared(
										pthread_mutexattr_t* attr,
										int pshared);
  • 返回:成功返回0,否则返回错误编号
  • 参数:
    • attr:互斥锁属性
    • pshared:进程共享属性
      • PTHREAD_PROCESS_PRIVATE(默认情况)
        • 锁只能用于一个进程内部的多个线程进行互斥
      • PTHREAD_PROCESS_SHARED
        • 锁可以用于两个不同进程中的线程进行互斥
  1. 互斥锁类型操作
#include <pthread.h>

int pthread_mutexattr_gettype(
										const pthread_mutexattr_t* restrict attr,
										int* restrict type);
										
int pthread_mutexattr_settype(
										pthread_mutexattr_t* attr,
										int type);
  • 返回:成功返回0,否则返回错误编号
  • 参数:
    • attr:互斥锁属性
    • type:互斥锁类型
      • 标准互斥锁:PTHREAD_MUTEX_NORMAL
        • 第一次上锁成功,第二次上锁会阻塞。
      • 递归互斥锁:PTHREAD_MUTEX_RECURSIVE
        • 第一次上锁成功,第二次以后上锁还是成功,内部计数。
      • 检错互斥锁:PTHREAD_MUTEX_ERRORCHECK
        • 第一次上锁成功,第二次上锁会出错。
      • 默认互斥锁:PTHREAD_MUTEX_DEFAULT(同标准互斥锁)

示例

/*
 * lock_type.c
 * 互斥锁类型
 */

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
	pthread_mutex_t mutex;
	
	if(argc<2){
		printf("-usage:%s [error|normal|recursive]\\n",argv[0]);exit(1);
	}
	
	//定义互斥锁属性
	pthread_mutexattr_t mutexattr;
	//初始化互斥锁属性
	pthread_mutexattr_init(&mutexattr);
	//check argv传入的互斥锁类型
	if(!strcmp(argv[1],"error")){
		//设置互斥锁类型
		pthread_mutexattr_settype(&mutexattr,\\
		PTHREAD_MUTEX_ERRORCHECK);
		}
	else if(!strcmp(argv[1],"normal")){
		pthread_mutexattr_settype(&mutexattr,\\
		PTHREAD_MUTEX_NORMAL);
		}
	else if(!strcmp(argv[1],"recursive")){
		pthread_mutexattr_settype(&mutexattr,\\
		PTHREAD_MUTEX_RECURSIVE);
		}
	
	//按指定类型初始化互斥锁
	pthread_mutex_init(&mutex,&mutexattr);
	//上锁
	if(pthread_mutex_lock(&mutex)!=0)
	printf("lock failure\\n");
	else
	printf("lock success\\n");
	//第二次上锁
	if(pthread_mutex_lock(&mutex)!=0)
	printf("lock failure\\n");
	else
	printf("lock success\\n");
	//上两次锁,也需要释放两次
	pthread_mutex_unlock(&mutex);
	pthread_mutex_unlock(&mutex);
	
	//销毁互斥锁和属性
	pthread_mutexattr_destroy(&mutexattr);
	pthread_mutex_destroy(&mutex);
	
	return 0;
}


输出:

$ ./lock_type error
lock success
lock failure
$ ./lock_type recursive
lock success
lock success
$ ./lock_type normal
lock success

^C
$

线程互斥——读写锁

  1. 概念
  • 线程使用互斥锁缺乏读并发性。
  • 当读操作较多,写操作较少时,可使用读写锁提高线程读并发性。
  • 读写锁数据类型
    • pthread_rwlock_t
  1. 读写锁创建和销毁
#include <pthread.h>

int pthread_rwlock_init(pthread_rwlock_t* restrict rwlock,\\
						const pthread_rwlockattr_t* restrict attr);
						
int pthread_rwlock_destroy(pthread_rwlock_t* rwlock);

  • 返回:成功返回0,否则返回错误编号
  • 参数:
    • rwlock:读写锁
    • attr:读写锁属性
  1. 读写锁加锁和解锁
#include <pthread.h>
//功能:加读锁
int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);

//功能:加写锁
int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);

//功能:释放锁
int pthread_rwlock_unlock(pthread_rwlock_t* rwlock);

  • 返回:成功返回0,否则返回错误编号
  • 参数:
    • rwlock:读写锁
  1. 示例:
/*
 * rwlock_feature.c
 * 
 */

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//定义读写锁
pthread_rwlock_t rwlock;

int main(int argc, char **argv)
{
	if(argc<3){
		printf("-usage:%s [r|w] [r|w]\\n",argv[0]);
		exit(1);
	}
	//读写初始化
	pthread_rwlock_init(&rwlock,NULL);
	
	if(!strcmp("r",argv[1])){
		//加读锁
		if(pthread_rwlock_rdlock(&rwlock) != 0)
		{printf("first read lock failure\\n");}
		else
		{printf("first read lock success\\n");}
	}
	
	if(!strcmp("w",argv[1])){
		//加写锁
		if(pthread_rwlock_wrlock(&rwlock) != 0)
		{printf("first write lock failure\\n");}
		else
		{printf("first write lock success\\n");}
	}
	
	if(!strcmp("r",argv[2])){
		//加读锁
		if(pthread_rwlock_rdlock(&rwlock) != 0)
		{printf("second read lock failure\\n");}
		else
		{printf("second read lock success\\n");}
	}
	
	if(!strcmp("w",argv[2])){
		//加写锁
		if(pthread_rwlock_wrlock(&rwlock) != 0)
		{printf("second write lock failure\\n");}
		else
		{printf("second write lock success\\n");}
	}
	
	//释放读写锁
	pthread_rwlock_unlock(&rwlock);
	pthread_rwlock_unlock(&rwlock);
	
	return 0;
}


输出:

$ ./rwlock_feature r r
first read lock success
second read lock success

$ ./rwlock_feature r w
first read lock success
^C

$ ./rwlock_feature w w
first write lock success
second write lock failure

$ ./rwlock_feature w r
first write lock success
second read lock failure

分析:

  • 读和读:不排斥
  • 读和写\\写和读:排斥(后一个线程阻塞或失败)
  • 写和写:排斥

以上是关于Linux线程互斥的主要内容,如果未能解决你的问题,请参考以下文章

(转载)Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)

Linux下线程同步(带你了解什么是互斥锁死锁读写锁条件变量信号量等)

C POSIX 线程的互斥体/条件的工作方式因变量所在的位置而异

如果我想制作分布式互斥库,我是不是必须创建一个线程?

Linux多线程同步之互斥量和条件变量

Linux学习_线程的互斥