1、线程属性
•
int
pthread_attr_init
(
pthread_attr_t
*
attr
);
•
int
pthread_attr_destroy
(
pthread_attr_t
*
attr
);
•
涉及分离状态、堆栈起始地址、堆栈大小、警戒区域大小、并发级别
•
设置
/
获取分离状态
•
int
pthread_attr_getdetachstate
(
const
pthread_attr_t
*restrict
attr
,
int
*
detachstate
);
•
int
pthread_attr_setdetachstate
(
pthread_attr_t
*
attr
,
int
detachstate
);
2、同步对象的属性
•
互斥体属性
•
允许一个互斥体在多个
进程
间共享
•
int
pthread_mutexattr_getpshared
(
const
pthread_mutexattr_t
*restrict
attr
,
int
*restrict
pshared
);
•
int
pthread_mutexattr_setpshared
(
pthread_mutexattr_t
*
attr
,
int
pshared
);
•
int
pthread_mutexattr_gettype
(
const
pthread_mutexattr_t
*restrict
attr
,
int
*restrict type);
•
int
pthread_mutexattr_settype
(
pthread_mutexattr_t
*
attr
,
int
type);
•
对于
PTHREAD_MUTEX_RECURSIVE
类型,允许一个互斥体被同一个线程多次加锁
•
读写锁属性:
允许一个读写锁在多个
进程
间共享
•
条件变量属性:
允许一个条件变量在多个
进程
间共享
3、可重入-线程安全
•
指函数可以同时被多个线程安全的调用
•
注意不要在函数内使用静态数据
4、特定于线程的数据
•
又称为线程私有数据
•
创建一个
key
,确保只能被调用一次,正确的调用序列
void destructor(void *);
pthread_key_t key;
pthread_once_t init_done = PTHREAD_ONCE_INIT;
void
thread_init(void)
{
err = pthread_key_create(&key, destructor);
}
int
threadfunc(void *arg)
{
pthread_once(&init_done, thread_init);
...
}
•
与
key
绑定地址
•
void *
pthread_getspecific
(
pthread_key_t
key);
•
int
pthread_setspecific
(
pthread_key_t
key,
const
void *value);
5、cancel选项
•
设置
cancel
状态,允许
cancel
或禁止
cancel
•
int
pthread_setcancelstate
(
int
state,
int
*
oldstate
);
•
设置
cancel
类型,延迟
cancel
或立即
cancel
•
int
pthread_setcanceltype
(
int
type,
int
*
oldtype
);
•
缺省为延迟
cancel
:
cancel
请求被暂时挂起,只有线程执行到某些特定的函数时,才能被
cancel
•
void
pthread_testcancel
(void); //
增加一个
cancel
点
•
立即
cancel
:允许线程被随时终止
6、线程与信号
•
每个线程有自己的信号掩码,但是信号的处理动作是整个进程共享的
•
信号只递交给单个线程,对于硬件故障或定时器信号,递交给对应的线程;其它信号,递交给一个随机的线程
•
改变线程的信号屏蔽
•
int
pthread_sigmask
(
int
how,
const
sigset_t
*restrict set,
sigset_t
*restrict
oset
);
•
int
sigwait
(
const
sigset_t
*restrict set,
int
*restrict
signop
); //
等待信号发生
•
int
pthread_kill
(
pthread_t
thread,
int
signo
); //
想线程发送信号
•
创建一个线程,专职处理信号
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
int quitflag; /* set nonzero by thread */
sigset_t mask;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t wait = PTHREAD_COND_INITIALIZER;
void *thr_fn(void *arg)
{
int err, signo;
for (;;)
{
err = sigwait(&mask, &signo);
if (err != 0) printf("%d, %s\n", err, "sigwait failed");
switch (signo)
{
case SIGINT:
printf("\ninterrupt\n");
break;
case SIGQUIT:
pthread_mutex_lock(&lock);
quitflag = 1;
pthread_mutex_unlock(&lock);
pthread_cond_signal(&wait);
return(0);
default:
printf("unexpected signal %d\n", signo);
exit(1);
}
}
}
int main(void)
{
int err;
sigset_t oldmask;
pthread_t tid;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);
if ((err = pthread_sigmask(SIG_BLOCK, &mask, &oldmask)) != 0)
printf("%d, %s\n", err, "SIG_BLOCK error");
err = pthread_create(&tid, NULL, thr_fn, 0);
if (err != 0) printf("%d, %s\n", err, "can't create thread");
pthread_mutex_lock(&lock);
while (quitflag == 0)
pthread_cond_wait(&wait, &lock);
pthread_mutex_unlock(&lock);
/* SIGQUIT has been caught and is now blocked; do whatever */
quitflag = 0;
/* reset signal mask which unblocks SIGQUIT */
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
perror("SIG_SETMASK error");
exit(0);
}
7、线程与fork
•
fork
后,子进程中只存在一个线程,同时继承了互斥体、读写锁、条件变量
•
子进程需要清理继承的同步对象
•
int
pthread_atfork
(void (*prepare)(void), void (*parent)(void), void (*child)(void));
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
void prepare(void)
{
printf("preparing locks...\n");
pthread_mutex_lock(&lock1);
pthread_mutex_lock(&lock2);
}
void parent(void)
{
printf("parent unlocking locks...\n");
pthread_mutex_unlock(&lock1);
pthread_mutex_unlock(&lock2);
}
void child(void)
{
printf("child unlocking locks...\n");
pthread_mutex_unlock(&lock1);
pthread_mutex_unlock(&lock2);
}
void *thr_fn(void *arg)
{
printf("thread started...\n");
pause();
return(0);
}
int main(void)
{
int err;
pid_t pid;
pthread_t tid;
#if defined(BSD) || defined(MACOS)
printf("pthread_atfork is unsupported\n");
#else
if ((err = pthread_atfork(prepare, parent, child)) != 0)
printf("%d, %s\n", err, "can't install fork handlers");
err = pthread_create(&tid, NULL, thr_fn, 0);
if (err != 0) printf("%d, %s\n", err, "can't create thread");
sleep(2);
printf("parent about to fork...\n");
if ((pid = fork()) < 0)
perror("fork failed");
else if (pid == 0) /* child */
printf("child returned from fork\n");
else /* parent */
printf("parent returned from fork\n");
#endif
exit(0);
}
8、线程与I/O
•
pread
()
与
pwrite
()
函数在多线程环境中非常有用,原子操作