linux线程控制

1.线程属性

a) 分离状态

不需要了解线程返回终止状态时设置

b) 栈末尾警戒缓冲区

避免栈溢出的扩展内存大小,一般系统设置为页的整数倍

c) 栈的最小地址

i. 当有许多线程时,减少栈大小

ii. 当线程中有许多自动变量时,则增大栈大小

d) 栈的最小长度

2.互斥量属性

a) 进程共享属性

i. 默认:PTHREAD_PROCESS_PRIVATE,多线程访问同一个同步对象。

ii. PTHREAD_PROCESS_SHARED,多进程将锁映射到自己空间,实现多进程同步

b) 健壮属性(解决:多进程间,持有的进程终止时,互斥量锁定,其他进程阻塞)

i. 默认:PTHREAD_MUTEX_STALLED,进程会被拖住

ii. PTHREAD_MUTEX_ROBUST,进程终止时未解锁,从pthread_mutex_lock()的返回值为EOWNERDEAD而不是0,通过返回值进行恢复处理。(恢复时线程先调用pthread_mutex_consistent&m_lock,再进行pthread_mutex_unlock(&m_lock)解锁;否则应用状态无法恢复,解锁后,互斥量将永久不可以)

c) 类型属性

PTHREAD_MUTEX_RECURSIVE:可用于递归

 

3.读写锁,条件变量,屏障属性

只支持进程共享属性

4.线程与信号(信号处理是进程中所有线程共享的)

Linux多线程中使用信号-2

http://blog.csdn.net/QQ276592716/article/details/7325264

在多线程中处理信号的原则却完全不同,它的基本原则是:将对信号的异步处理,转换成同步处理,也就是说用一个线程专门的来同步等待信号的到来,而其它的线程可以完全不被该信号中断/打断(interrupt)。这样就在相当程度上简化了在多线程环境中对信号的处理。而且可以保证其它的线程不受信号的影响。

sigwait函数使用一个信号集作为他的参数,并且在集合中的任一个信号发生时返回该信号值,解除阻塞,然后可以针对该信号进行一些相应的处理。

在多线程程序中,一个线程可以使用pthread_kill对同一个进程中指定的线程(包括自己)发送信号。

 在多线程代码中,总是使用sigwait或者sigwaitinfo或者sigtimedwait等函数来处理信号。

可以使用pthread_sigmask函数来屏蔽某个线程对某些信号的 响应处理,仅留下需要处理该信号的线程来处理指定的信号。实现方式是:利用线程信号屏蔽集的继承关系(在主进程中对sigmask进行设置后,主进程创建出来的线程将继承主进程的掩码

调用sigwait同步等待的信号必须在调用线程中被屏蔽,并且通常应该在所有的线程中被屏蔽(这样可以保证信号绝不会被送到除了调用sigwait的任何其它线程),这是通过利用信号掩码的继承关系来达到的。

1. static void * sig_thread(void *arg)

2. {

3.       sigset_t *set = (sigset_t *) arg;

4.       int s, sig;

5. 

6.       for (;;) {

7.             s = sigwait(set, &sig);

8.             if (!= 0)

9.                   handle_error_en(s, "sigwait");

10.             printf("Signal handling thread got signal %d\n", sig);

11.       }

12. }

13. 

14. int 

1. main(int argc, char *argv[])

15. {

16.       pthread_t thread;

17.       sigset_t set;

18.       int s;

19. 

20.       /* 

21.          Block SIGINT; other threads created by main() will inherit

22.          a copy of the signal mask. 

23.        */

24.       sigemptyset(&set);

25.       sigaddset(&set, SIGQUIT);

26.       sigaddset(&set, SIGUSR1);

27.       s = pthread_sigmask(SIG_BLOCK, &set, NULL);

28.       if (!= 0)

29.             handle_error_en(s, "pthread_sigmask");

30.       s = pthread_create(&thread, NULL, &sig_thread, (void *) &set);

31.       if (!= 0)

32.             handle_error_en(s, "pthread_create");

33.       /* 

34.         Main thread carries on to create other threads and/or do

35.         other work 

36.        */

37.       pause(); /* Dummy pause so we can test program */

38.       return 0;

39. }

通过在主线程中阻塞一些信号,其它的线程会继承信号掩码,然后专门用一个线程使用sigwait函数来同步的处理信号,使其它的线程不受到信号的影响。

 

 

1. digdeep@ubuntu:~/pthread$ gcc -Wall -pthread -o sigwait_test sigwait_test.

2. digdeep@ubuntu:~/pthread$ ./sigwait_test 

3. Receive signal. 10

4. Receive signal. 12

5. Receive signal. 34

6. Receive signal. 34

7. Receive signal. 36

8. Receive signal. 36

9. Receive signal. 64

10. Receive signal. 64

11. digdeep@ubuntu:~/pthread$

从以上测试程序发现以下规则:

· 对于非实时信号,相同信号不能在信号队列中排队;对于实时信号,相同信号可以在信号队列中排队

· 如果信号队列中有多个实时以及非实时信号排队,实时信号并不会先于非实时信号被取出信号数字小的会先被取出:如 SIGUSR110)会先于SIGUSR2 (12)SIGRTMIN34)会先于SIGRTMAX (64), 非实时信号因为其信号数字小而先于实时信号被取出。

 

 

· 不要在线程的信号掩码中阻塞不能被忽略处理的两个信号 SIGSTOPSIGKILL

· 不要在线程的信号掩码中阻塞 SIGFPESIGILLSIGSEGVSIGBUS

· 确保 sigwait() 等待的信号集已经被进程中所有的线程阻塞

· 在主线程或其它工作线程产生信号时,必须调用 kill() 将信号发给整个进程,而不能使用 pthread_kill() 发送某个特定的工作线程,否则信号处理线程无法接收到此信号。

· 因为 sigwait()使用了串行的方式处理信号的到来,为避免信号的处理存在滞后,或是非实时信号被丢失的情况,处理每个信号的代码应尽量简洁、快速,避免调用会产生阻塞的库函数。

5.线程与fork

子进程继承了父进程的互斥量、读写锁、条件变量的条件状态

若子进程fork后立马调用exec可避免死锁等问题;

可通过int pthread_atfork(void (*prepare)(void),void (*parent)(void),void (*child)(void));清理锁的状态。

prepare:获取父进程定义的锁;(父进程在fork创建子进程前调用)

Parent:对获取的锁进行解锁;(父进程在fork创建子进程后,返回父进程前调用)

Child对获取的锁进行解锁;(父进程在fork返回子进程前调用)

#include<pthread.h>

pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZED;

pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZED;

void prepare(void)

{

int err;

printf("prepare\n");

if((err = pthread_mutex_lock(&lock1))!= 0){printf("prepare1 err\n");}

if((err = pthread_mutex_lock(&lock2))!= 0){printf("prepare2 err\n");}

}

void parent(void)

{

int err;

printf("parent\n");

if((err = pthread_mutex_unlock(&lock1))!= 0){printf("parent1 err\n");}

if((err = pthread_mutex_unlock(&lock2))!= 0){printf("parent2 err\n");}

}

void child(void)

{

int err;

printf("child\n");

if((err = pthread_mutex_unlock(&lock1))!= 0){printf("child1 err\n");}

if((err = pthread_mutex_unlock(&lock2))!= 0){printf("child2 err\n");}

}

void *thr_func(void *arg)

{

printf("thread run\n");

pause();

return(0);

}

int main()

{

int err;

pid_t pid;

pthread_t tid;

if((err = pthread_atfork(prepare,parent,child))!=0){printf("pthread_atfork  err\n");exit(1);}

if((err = pthread_create(&tid,NULL,thr_func,NULL))!=0){printf("pthread_create  err\n");exit(1);}

sleep(2);

printf("parent to fork\n");

if((pid = fork()) < 0){printf("pthread_create  err\n");exit(1);}

else if(pid == 0){printf("child return from fork\n");}

else {printf("parent return from fork\n");}

exit(0);

}

结果是:

fork()-->prepare()-->child()--->pid=0---->parent()---->pid>0

猜你喜欢

转载自blog.csdn.net/qq_14814909/article/details/76215317
今日推荐