互斥量:
允许程序员锁住某个对象,使得每次只能有一个线程访问它.
mutex是一种保证串行的睡眠锁,当无法获得锁时,mutex挂起当前线程,进入阻塞状态。正因为此,不能再中断上线文中使用。
不可以重复获取同一把锁,不可以多次释放同一把锁
在多进程中资源共享使使用,保护临界资源。在使用前加锁,使用后解锁。同时要避免死锁。
互斥量相关的函数
#include<pthread.h>
//初始化
int pthread_mutex_init(pthread_mutex_t mutex,const pthread_mutexattr_t *mutexattr);
//加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
//解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
//销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex)
尝试获得锁的区别
//成功返回0,失败返回错误码。如果互斥量已经被其他线程锁住,会导致该线程阻塞
int pthread_mutex_lock(pthread_mutex_t *mutex);
//如果互斥量被锁住,这个函数不会阻塞线程
int pthread_mutex_trylock(pthread_mutex_t *mutex);
测试代码
实例中的临界区资源 work_area,time_to_exit
主线程获取输入,子线程统计字符串大小
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<semaphore.h>
#include<pthread.h>
void *thread_function(void *arg);
pthread_mutex_t work_mutex;
#define WORK_SIZE 1024
char work_area[WORK_SIZE];
int time_to_exit = 0;
int main()
{
int res;
pthread_t a_thread;
void *thread_result;
memset(work_area,0,sizeof(work_area));
res = pthread_mutex_init(&work_mutex,NULL);
if(res != 0)
{
perror("Semaphore initialization failed\n");
exit(EXIT_FAILURE);
}
res = pthread_create(&a_thread,NULL,thread_function,NULL);
if(res !=0)
{
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
pthread_mutex_lock(&work_mutex);
printf("Input some txt,Enter 'end' to finish\n");
while(!time_to_exit)
{
fgets(work_area,WORK_SIZE,stdin);
pthread_mutex_unlock(&work_mutex);
while(1)
{
pthread_mutex_lock(&work_mutex);
if(work_area[0] != '\0')
{
pthread_mutex_unlock(&work_mutex);
sleep(1);
}
else
break;
}
}
pthread_mutex_unlock(&work_mutex);
printf("\n Waiting for thread to finish...\n");
res = pthread_join(a_thread,&thread_result);
if(res !=0)
{
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joined\n");
pthread_mutex_destroy(&work_mutex);
exit(EXIT_SUCCESS);
}
void *thread_function(void *arg)
{
sleep(1);
pthread_mutex_lock(&work_mutex);
while(strncmp("end",work_area,3) != 0)
{
printf("You input %d characters\n",strlen(work_area) -1);
work_area[0]='\0';
pthread_mutex_unlock(&work_mutex);
sleep(1);
pthread_mutex_lock(&work_mutex);
while(work_area[0] == '\0'){
pthread_mutex_unlock(&work_mutex);
sleep(1);
pthread_mutex_lock(&work_mutex);
}
}
time_to_exit = 1;
work_area[0]='\0';
pthread_mutex_unlock(&work_mutex);
pthread_exit(0);
}
打印输出
(base) wy@ubuntu:~/process$ ./thread4
Input some txt,Enter 'end' to finish
hello
You input 5 characters
end
Waiting for thread to finish...
Thread joined
子线程等待主线程的输入并统计输入字符串work_area的长度。
子线程在统计后将time_to_exit 置位,使主线程退出。
死锁举例
ABBA锁
1、进程之间
在一个线程中对已经加锁的普通锁再次加锁->死锁
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
int a = 0;
int b = 0;
pthread_mutex_t mutex_a;
pthread_mutex_t mutex_b;
void* another( void* arg )
{
pthread_mutex_lock( &mutex_b );
printf( "in child thread, got mutex b, waiting for mutex a\n" );
sleep( 5 );
++b;
pthread_mutex_lock( &mutex_a );
b += a++;
pthread_mutex_unlock( &mutex_a );
pthread_mutex_unlock( &mutex_b );
pthread_exit( NULL );
}
int main()
{
pthread_t id;
pthread_mutex_init( &mutex_a, NULL );
pthread_mutex_init( &mutex_b, NULL );
pthread_create( &id, NULL, another, NULL );
pthread_mutex_lock( &mutex_a );
printf( "in parent thread, got mutex a, waiting for mutex b\n" );
sleep( 5 );
++a;
pthread_mutex_lock( &mutex_b );
a += b++;
pthread_mutex_unlock( &mutex_b );
pthread_mutex_unlock( &mutex_a );
pthread_join( id, NULL );
pthread_mutex_destroy( &mutex_a );
pthread_mutex_destroy( &mutex_b );
return 0;
}
主线程加锁mutex_a 保护变量a, 主线程加锁mutex_b,与此同时子线程先加锁mutex_b,再加锁mutex_a。两个线程僵持住。
程序执行卡住
root@ubuntu:/home/wy/network# ./a.out
in parent thread, got mutex a, waiting for mutex b
in child thread, got mutex b, waiting for mutex a
2、线程和进程之间
子进程可能不清楚父进程继承而来的互斥锁的具体加锁/解锁状态。
在父进程中已经加锁了,子线程中再次加锁导致死锁。
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <wait.h>
pthread_mutex_t mutex;
//线程中
void* another( void* arg )
{
printf( "in child thread, lock the mutex\n" );
pthread_mutex_lock( &mutex );
sleep( 5 );
pthread_mutex_unlock( &mutex );
}
int main()
{
pthread_mutex_init( &mutex, NULL );
pthread_t id;
pthread_create( &id, NULL, another, NULL );
sleep( 1 );
int pid = fork();
if( pid < 0 )
{
pthread_join( id, NULL );
pthread_mutex_destroy( &mutex );
return 1;
}
else if( pid == 0 )
{
printf( "I anm in the child, want to get the lock\n" );
pthread_mutex_lock( &mutex );
printf( "I can not run to here, oop...\n" );
pthread_mutex_unlock( &mutex );
exit( 0 );
}
else
{
pthread_mutex_unlock( &mutex );
wait( NULL );
}
pthread_join( id, NULL );
pthread_mutex_destroy( &mutex );
return 0;
}
# ./a.out
in child thread, lock the mutex
I anm in the child, want to get the lock