Linux学习_线程的死锁和信号

Posted Leslie X徐

tags:

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

线程的死锁,信号的概念

死锁

  1. 概念
  • 死锁:
    • 两个线程试图同时占用两个资源,并按不同的次序锁定相应的共享资源。
  • 解决方式:
    • 按相同的次序锁定相应的共享程序。
    • 使用函数pthread_mutex_trylock(),它是函数函数pthread_mutex_lock()的非阻塞函数。
  1. 示例:
/*
 * dead_lock.c
 * 
 * 
 */

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

//两个共享资源
typedef struct
{
	int value;
	pthread_mutex_t mutex;
}ResourceA;

typedef struct
{
	int value;
	pthread_mutex_t mutex;
}ResourceB;

typedef struct
{
	ResourceA *ra;
	ResourceB *rb;
}Storage;

void* a_fun(void* arg)
{
	Storage *s = (Storage*)arg;
	//对ResouceA加锁
	pthread_mutex_lock(&s->ra->mutex);
	printf("0x%lx is waiting for ResouceB...\\n",pthread_self());
	sleep(1);
	
	//对ResouceB加锁
	pthread_mutex_lock(&s->rb->mutex);
	++s->rb->value;
	printf("ResouceA value is:%d\\n",s->ra->value);
	printf("ResouceB value is:%d\\n",s->rb->value);
	pthread_mutex_unlock(&s->ra->mutex);
	pthread_mutex_unlock(&s->rb->mutex);
	return (void*)0;
}

void* b_fun(void* arg)
{
	Storage *s = (Storage*)arg;
	
	//-------------------------死锁程序-----------------------------
	//对ResouceB加锁
	//pthread_mutex_lock(&s->rb->mutex);
	//sleep(1);
	//printf("0x%lx is waiting for ResouceA...\\n",pthread_self());
	对ResouceA加锁
	//pthread_mutex_lock(&s->ra->mutex);
	//printf("ResouceA value is:%d\\n",s->ra->value);
	//printf("ResouceB value is:%d\\n",s->rb->value);
	//pthread_mutex_unlock(&s->ra->mutex);
	//pthread_mutex_unlock(&s->rb->mutex);
	
	//--------------------------正常程序------------------------------
	//对ResouceA加锁
	pthread_mutex_lock(&s->ra->mutex);
	printf("0x%lx is waiting for ResouceA...\\n",pthread_self());
	sleep(1);
	
	//对ResouceB加锁
	pthread_mutex_lock(&s->rb->mutex);
	++s->ra->value; 
	printf("ResouceA value is:%d\\n",s->ra->value);
	printf("ResouceB value is:%d\\n",s->rb->value);
	pthread_mutex_unlock(&s->ra->mutex);
	pthread_mutex_unlock(&s->rb->mutex);
	return (void*)0;
}



int main(int argc, char **argv)
{
	ResourceA ra;
	ResourceB rb;
	ra.value = 100;
	rb.value = 200;
	pthread_mutex_init(&ra.mutex, NULL);
	pthread_mutex_init(&rb.mutex, NULL);
	Storage s={&ra, &rb};
	
	printf("ResouceA value is:%d\\n",ra.value);
	printf("ResouceB value is:%d\\n",rb.value);
	
	int err;
	pthread_t	thread_a, thread_b;
	err = pthread_create(&thread_a, NULL, a_fun, (void*)&s);
	if(err)
	{fprintf(stderr, "pthread_create:%s\\n",strerror(0));exit(1);}
	
	err = pthread_create(&thread_b, NULL, b_fun, (void*)&s);
	if(err)
	{fprintf(stderr, "pthread_create:%s\\n",strerror(0));exit(1);}
	
	pthread_join(thread_a,NULL);
	pthread_join(thread_b,NULL);
	
	pthread_mutex_destroy(&ra.mutex);
	pthread_mutex_destroy(&rb.mutex);
	
	return 0;
}


输出:

ResouceA value is:100
ResouceB value is:200
0xb6ddf460 is waiting for ResouceB...
ResouceA value is:100
ResouceB value is:201
0xb65de460 is waiting for ResouceA...
ResouceA value is:101
ResouceB value is:201

线程和信号

  1. 概念
  • 进程中每个线程都有自己的信号屏蔽字和信号未决字
  • 信号的处理方式是进程中所有线程共享的
  • 进程中的信号是递送到单个线程的
  • 定时器是进程资源,进程中所有的线程共享相同的定时器
  • 子线程调用alarm()函数产生的alarm信号发送给主控线程。
  1. 函数原型
#include <signal.h>
int pthread_sigmask(
								int how,
								const sigset_t* restrict set,
								sigset_t* restrict oset);
								
  • 功能:线程的信号屏蔽
  • 返回:成功返回0,出错返回错误编号
  1. 案例
/*
 * pthread_alarm.c
 * 
 * 主线程睡眠10秒,子线程2秒输出一个信号
 */

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

void sig_handle(int signo)
{
	printf("pthread id in the sig_handler: %lx\\n",pthread_self());
	if(signo==SIGALRM) printf("timeout...\\n");
	alarm(2);
}

void* th_fn(void* arg)
{
	if(signal(SIGALRM, sig_handle)==SIG_ERR) perror("error");
	
	//在子线程中设置定时器,若不设置则无法接收信号
	alarm(2);
	
	int i;
	for(i=1;i<=100;++i){
		printf("(%lx) i: %d\\n",pthread_self(),i);
		sleep(1);
	}
	
	return (void*)0;
}

int main(int argc, char **argv)
{
	pthread_t th;
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	
	int err=pthread_create(&th, &attr, th_fn, (void*)0);
	if(err)perror("error");
	
	sigset_t set;
	sigemptyset(&set);
	sigaddset(&set, SIGALRM);
	//对主控线程屏蔽SIGALRM信号
	pthread_sigmask(SIG_SETMASK, &set, NULL);
	
	while(1){
		printf("control thread(%lx) is running...\\n",pthread_self());
		sleep(10); 
		//睡眠中主控信号接收到信号会中断睡眠继续运行
	}
	printf("control thread over\\n");
	return 0;
}

输出:

control thread(b6fa70c0) is running...
(b6dd3460) i: 1
(b6dd3460) i: 2
pthread id in the sig_handler: b6dd3460
timeout...
(b6dd3460) i: 3
(b6dd3460) i: 4
pthread id in the sig_handler: b6dd3460
timeout...
(b6dd3460) i: 5
(b6dd3460) i: 6
pthread id in the sig_handler: b6dd3460
timeout...
(b6dd3460) i: 7
(b6dd3460) i: 8
pthread id in the sig_handler: b6dd3460
timeout...
(b6dd3460) i: 9
(b6dd3460) i: 10
control thread(b6fa70c0) is running...
pthread id in the sig_handler: b6dd3460
timeout...
(b6dd3460) i: 11
(b6dd3460) i: 12
pthread id in the sig_handler: b6dd3460
timeout...
(b6dd3460) i: 13
^C

以上是关于Linux学习_线程的死锁和信号的主要内容,如果未能解决你的问题,请参考以下文章

Linux学习_线程信号量

Linux学习_线程的概念创建和终止

linuxbingc(多线程)

linuxbingc(多线程)

linuxbingc(多线程)

Linux学习_线程的互斥