Linux 下C语言多线程编程--互斥锁

互斥锁

  • 互斥锁用来保证一段时间内只有一个线程在执行一段代码(保证共享数据的完整性)

  • 互斥锁变量

    typedef union{
     	struct __pthread_mutex_s __data;
    	char __size[__SIZEOF_PTHREAD_MUTEX_T];
    	long int __align;
    } pthread_mutex_t;
    
  • 互斥锁的生成

    /* Initialize a mutex.  */
    extern int pthread_mutex_init (pthread_mutex_t *__mutex,
    			       const pthread_mutexattr_t *__mutexattr)
    	 __THROW __nonnull ((1));
    

    用于动态创建一个互斥锁,第一个参数为互斥锁指针,第二个参数为互斥锁属性(通常传NULL表示默认属性)

互斥锁属性

  • 属性结构

    /* Data structures for mutex handling.  The structure of the attribute
    type is not exposed on purpose.  */
    typedef union{
     	char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
    	int __align;
    } pthread_mutexattr_t;
    

    互斥锁属性使用上面的联合体存放,通过函数pthread_mutexattr_setpshared()设置范围属性,

  • 范围属性

    /* Process shared or private flag.  */
    enum{
    	PTHREAD_PROCESS_PRIVATE,//同进程中线程同步
    	#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE
    	PTHREAD_PROCESS_SHARED //不同进程中的线程同步
    	#define PTHREAD_PROCESS_SHARED  PTHREAD_PROCESS_SHARED
    };
    
  • 类型属性
    通过函数pthread_mutexattr_settype()(通常使用默认属性PTHREAD_MUTEX_DEFAULT

    /* Mutex types.  */
    enum{
    	//缺省值,普通锁,当一个线程加锁以后,其余请求锁的线程将会形成一个等待队列
    	//并在解锁后按照先后顺序获得锁,资源分配公平
    	PTHREAD_MUTEX_TIMED_NP,
    	//嵌套锁,允许同一线程对同一锁成功获得多次,并通过多次unlock解锁
    	//如果是不同线程请求,则在加锁线程解锁时重新竞争
    	PTHREAD_MUTEX_RECURSIVE_NP,
    	//检错锁,如果同一线程请求同一个锁,则返回EDEALK
    	//否则与普通锁类型动作相同,这样保证当不允许多次时,不会出现最简单的死锁
    	PTHREAD_MUTEX_ERRORCHECK_NP,
    	//适应锁,动作最简单的类型,仅等待解锁以后重新竞争
    	PTHREAD_MUTEX_ADAPTIVE_NP
    	#if defined __USE_UNIX98 || defined __USE_XOPEN2K8
    	 ,
    	PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP,
    	PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
    	PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
    	PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
    	#endif
    	#ifdef __USE_GNU
    	 /* For compatibility.  */
    	, PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP
    	#endif
    };
    
  • Demo

    static void init_thread_mutex(void) {
    	pthread_mutexattr_t mutex_attr;
    	//PTHREAD_PROCESS_SHARED
    	pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_PRIVATE);
    	pthread_mutexattr_settype(&mutex_attr,PTHREAD_MUTEX_DEFAULT);
    	//使用上面的属性初始化thread_data_mutex互斥锁
    	pthread_mutex_init(&thread_data_mutex, &mutex_attr); 
    }
    

上锁操作

  • 加锁lock ()、解锁unlock()、测试加锁trylock()不论是哪种类型的锁,都不可能被两个不同的线程得到,而必须等待解锁,对于普通锁适应锁,解锁者可以说同进程内的任何线程,而对于检错锁必须由加锁者解锁,嵌套锁也是由加锁者解锁

  • 同一进程中的线程,如果枷锁后没有解锁,任何其他线程都无法在获得锁,也就是常说的死锁

  • 上锁

    /* Lock a mutex.  */
    extern int pthread_mutex_lock (pthread_mutex_t *__mutex)
    	 __THROWNL __nonnull ((1));
    

    当一个线程执行到pthread_mutex_lock处时,如果该锁此时被其他线程线程调用,那么此线程会阻塞,一直等另外一个线程释放锁,然后尝试请求锁。

  • 解锁

    /* Unlock a mutex.  */
    extern int pthread_mutex_unlock (pthread_mutex_t *__mutex)
    	 __THROWNL __nonnull ((1));
    

静态锁

  • 使用宏PTHREAD_MUTEX_INITIALIZER初始化

    pthread_mutex_t static_data_mutex = PTHREAD_MUTEX_INITIALIZER;
    
  • 静态锁初始化以后就可以直接使用,进行加锁解锁,和动态锁类型,唯一不用的是,当调用pthread_mutex_trylock()时,如果正忙则返回EBUSY而不是挂起等待

锁的销毁

  • 销毁锁,意味着释放它所占用的所有资源,且要求锁当前处于开发状态
    	* Destroy a mutex.  */
    	extern int pthread_mutex_destroy (pthread_mutex_t *__mutex)
      	 __THROW __nonnull ((1));
    
  • 在Liunx中,互斥锁不占用任何资源,因此Linux Threads中的pthread_mutex_destroy()除了检查锁的状态外没有其他任何操作(忙就返回EBUSY

完整Demo

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

//自定义数据结构,用于测试
typedef struct ThreadData_t {
    pthread_t m_pid;
    char* m_threadName;
} ThreadData;

ThreadData threadData;
pthread_mutex_t thread_data_mutex;
pthread_mutex_t static_data_mutex = PTHREAD_MUTEX_INITIALIZER;

static void init_thread_mutex(void) {
    pthread_mutexattr_t mutex_attr;
    //PTHREAD_PROCESS_SHARED
    pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_PRIVATE);
    pthread_mutexattr_settype(&mutex_attr,PTHREAD_MUTEX_DEFAULT);
    pthread_mutex_init(&thread_data_mutex, &mutex_attr); 
}

static void destory_thread_mutex(void) {
    pthread_mutex_destroy(&thread_data_mutex);
}
//线程函数routine
static void* test_thread1(void* thread_name) {
    fprintf(stderr, "%s try to lock!\n", (char*)thread_name);
    pthread_mutex_lock(&thread_data_mutex);
    threadData.m_pid = pthread_self();
    threadData.m_threadName = (char*)thread_name;
    fprintf(stderr, "%s mutex locked! \n", threadData.m_threadName);
    sleep(5);
    pthread_mutex_unlock(&thread_data_mutex);
    return NULL;
}

static void* test_thread2(void* thread_name) {
    fprintf(stderr, "%s try to lock!\n", (char*)thread_name);

    pthread_mutex_lock(&thread_data_mutex);
    threadData.m_pid = pthread_self();
    threadData.m_threadName = (char*)thread_name;
    fprintf(stderr, "%s mutex locked! \n", threadData.m_threadName);
    sleep(6);
    pthread_mutex_unlock(&thread_data_mutex);

    return NULL;
}
int main(int argc, char** argv) {
    pthread_t pid1, pid2;

    init_thread_mutex();

    if (pthread_create(&pid1, NULL, test_thread1, (void*)"test thread1") != 0) {
        fprintf(stderr, "create thread1 failed\n");
        return -1;
    }
    if (pthread_create(&pid2, NULL, test_thread2, (void*)"test thread2") != 0) {
        fprintf(stderr, "create thread2 failed\n");
        return -1;
    }
    pthread_join(pid1, NULL);
    pthread_join(pid2, NULL);

    destory_thread_mutex();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章