一、 线程和线程的同步
pthread_cancel(3)
#include<pthread.h>
intpthread_cancel(pthread_t thread);
Compile and linkwith -pthread.
功能:给一个线程发送终止的请求
参数:指定的线程id
返回值:0成功 错误返回错误码
线程的终止:有三种
return pthread_exit pthread_cancel 终止的信息是-1
pthread_detach(3)
#include<pthread.h>
intpthread_detach(pthread_t thread);
Compile and linkwith -pthread.
功能:标记一个线程为detached状态,当这个状态的线程终止的时候,线程的资源会被自动回收。(和join不能公用)
参数:thread:线程的id
返回值:0成功 错误返回错误码
举例
1 #include<stdio.h>
2 #include<pthread.h>
3
4 void *th_fn1(void *arg){
5 printf("thread1 returning...\n");
6 return (void *)1;
7 }
8 void *th_fn2(void *arg){
9 printf("thread2 exit...\n");
10 pthread_exit((void *)2);
11 }
12 void *th_fn3(void *arg){
13 while(1){
14 printf("thread3 exit...\n");
15 sleep(1);
16 }
17 }
18
19 int main(void){
20 pthread_t tid;
21 void *ret;
22 pthread_create(&tid,NULL,th_fn1,NULL);
23 pthread_join(tid,&ret);
24 printf("thread1 exit code%d\n",(int)ret);
25
26 pthread_create(&tid,NULL,th_fn2,NULL);
27 pthread_join(tid,&ret);
28 printf("thread2 exit code %d\n",(int)ret);
29
30 pthread_create(&tid,NULL,th_fn3,NULL);
31 pthread_cancel(tid);
32 pthread_join(tid,&ret);
33 printf("thread3 exit code %d\n",(int)ret);
34
35 pthread_create(&tid,NULL,th_fn1,NULL);
36 pthread_detach(tid);
37 return 0;
38 }
tarena@tarena-virtual-machine:~/day35$./join
thread1returning...
thread1 exitcode 1
thread2 exit...
thread2 exitcode 2
thread3 exit...
thread3 exitcode -1
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<pthread.h>
4 #define NLOOP 5
5 int counter=0;
6 void *doit(void *);
7 int main(void){
8 int i=0;
9 pthread_t tidA, tidB;
10 //创建两个线程
11 pthread_create(&tidA,NULL,&doit,NULL);
12 pthread_create(&tidB,NULL,&doit,NULL);
13 //等着线程的结束,以便回收资源
14 // pthread_join(tidA,NULL); (测试)
15 // pthread_join(tidB,NULL); (测试) 子线程相当于调用一个函数
16 printf("i=%d",i);
17 return 0;
18 }
19 void *doit(void *arg){
20 int i,val;
21 for(i=0;i<NLOOP;i++){
22 val=counter;
23 printf("%x:%d\n",(unsigned int)pthread_self(),val+1);
24 counter=val+1;
25 }
26 return NULL;
27 }
线程的同步:
同步的实现:
互斥锁:mutex锁
pthread_mutex_init(3)
需要对变量初始化和销毁
pthread_mutex_init(pthread_mutex_t *__mutex, __const pthread_mutexattr_t *__mutexattr)
pthread_mutex_destroy(pthread_mutex_t *__mutex)
功能:销毁Mutex指定的锁
参数:mutex 变量
pthread_mutex_trylock(pthread_mutex_t *__mutex)
尝试加锁
pthread_mutex_lock(pthread_mutex_t *__mutex)
举例:lock.c 两个线程进行同步,
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<pthread.h>
4 #define NLOOP 50
5 pthread_mutex_tc_mutex=PTHREAD_MUTEX_INITIALIZER;
6 int counter=0;
7 void *doit(void *);
8 int main(void){
9 pthread_t tidA, tidB;
10 //创建两个线程
11 pthread_create(&tidA,NULL,&doit,NULL);
12 pthread_create(&tidB,NULL,&doit,NULL);
13 //等着线程的结束,以便回收资源
14 pthread_join(tidA,NULL);
15 pthread_join(tidB,NULL);
16 return 0;
17 }
18 void *doit(void *arg){
19 int i,val;
20 static int counter;
21 for(i=0;i<NLOOP;i++){
22 pthread_mutex_lock(&c_mutex);
23 counter++;
24 printf("%x:%d\n",(unsignedint)pthread_self(),counter);
25 pthread_mutex_unlock(&c_mutex);
26 }
27 return NULL;
28 }
tarena@tarena-virtual-machine:~/day35$gcc lock.c -lpthread -o lock
tarena@tarena-virtual-machine:~/day35$./lock
b6d9ab40:1
b6d9ab40:2
b6d9ab40:3
b6d9ab40:4
b6d9ab40:5
b6d9ab40:6
b6d9ab40:7
b6d9ab40:8
….
….
b759bb40:98
b759bb40:99
b759bb40:100
如果不加锁可能会异步
22 // pthread_mutex_lock(&c_mutex);
23 counter++;
24 printf("%x:%d\n",(unsignedint)pthread_self(),counter);
25 // pthread_mutex_unlock(&c_mutex);
b6df1b40:1
b6df1b40:3
b6df1b40:4
b6df1b40:5
b6df1b40:6
….
b6df1b40:101
b75f2b40:2
b75f2b40:102
条件变量:(conditionbariable)
线程需要等待某个条件成立才能继续往下执行,条件不成立,线程就阻塞。等待另外一个线程将条件设置成成立,此时唤醒阻塞的线程,继续往下执行
pthread_cond_t类型的变量来表示条件变量
pthread_cond_init(3)
#include<pthread.h>
pthread_cond_tcond=PTHREAD_COND_INITIALIZER;
pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)
功能:初始化这个条件变量
参数:
Cond:条件变量的地址
Cond_attr:NULL
返回值:
Int pthread_cond_destroy (pthread_cond_t *cond);
功能:销毁条件变量
参数:cond:条件变量的地址
intpthread_cond_signal (pthread_cond_t *cond);
功能:唤醒在条件变量上等待的某个线程
int pthread_cond_broadcast(pthread_cond_t *cond)
功能:唤醒在条件变量上等待的全部线程
intpthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);
功能:等待条件成立
第一步:解锁mutex
第二步:阻塞等待
第三步:当被唤醒的时候,重新获得mutex锁
参数:cond条件变量
Mutex:mutex锁变量
intpthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,,const struct timespec *abstime)
功能:有时限的等待
参数:abstime 规定了等待的时限
演示一个生产者和消费者的例子。生产者生产一个结构体串在链表的头部,消费者从头部取走结构体
举例:pro-con.c
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<pthread.h>
4 typedef struct msg{
5 struct msg *next;
6 int num;
7 }msg_t;
8 msg_t *head;
9 //初始化锁和条件变量
10 pthread_cond_th_prod=PTHREAD_COND_INITIALIZER;
11 pthread_mutex_tlock=PTHREAD_MUTEX_INITIALIZER;
12 //生产者往链表的头部插入结点
13 void *producer(void *arg){
14 msg_t *mp;
15 for(;;){
16 mp=(msg_t *)malloc(sizeof(msg_t));
17 mp->num=rand()%1000+1;
18 printf("producer %d\n",mp->num);
19 //需要往链表里插入数据
20 pthread_mutex_lock(&lock);
21 mp->next=head;
22 head=mp;
23 //数据插入结束
24 pthread_mutex_unlock(&lock);
25 pthread_cond_signal(&h_prod);
26 sleep(rand()%5);
27 }
28 }
29 //消费者从链表的头部取走结点
30 void *consumer(void *arg){
31 msg_t *mp;
32 for(;;){
33 //先获得锁
34 pthread_mutex_lock(&lock);
35 //链表中没有结点的时候
36 while(head==NULL){
37 pthread_cond_wait(&h_prod,&lock);
38 }
39 mp=head;
40 head=head->next;//释放头结点
41 //解锁
42 pthread_mutex_unlock(&lock);
43 printf("consumer %d\n",mp->num);
44 free(mp);
45 mp=NULL;
46 sleep(rand()%5);
47 }
48 }
49 int main(void){
50 pthread_t tidp,tidc;
51 //创建两个线程
52 pthread_create(&tidp,NULL,producer,NULL);
53 pthread_create(&tidp,NULL,consumer,NULL);
54 //等待线程的结束
55 pthread_join(tidp,NULL);
56 pthread_join(tidc,NULL);
57 return 0;
58 }
producer 457
producer 43
consumer 43
consumer 457
producer 920
consumer 920
信号量:
既可以进程间通信,也可以线程间通信
mutex 非0即1
semaphore和mutex类似,表示可用资源的数量
使用sem_t类型表示信号量
sem_init(3)
Link with -lrt or -pthread.
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:初始化一个未命名的信号量
参数:
sem:要初始化的信号量
value:用value的值初始化信号量
pshared:0 用于多线程
返回值:
0表示成功。
-1表示失败,errno被设置
sem_wait(3)
#include <semaphore.h>
int sem_wait(sem_t *sem);
功能:使信号量-1,如果信号量大于0,则立即返回。若信号量等于1,阻塞等待。
参数:sem:指定的信号量
返回值:0表示成功。
-1表示失败,errno被设置
sem_destroy(3)
#include <semaphore.h>
int sem_destroy(sem_t *sem);
功能:销毁信号量
参数:sem:要销毁的信号量
返回值:0代表成功,-1代表失败,errno被设置
sem_trywait(3)
int sem_trywait(sem_t *sem);
非阻塞,其它同sem_wait
sem_post(3)
int sem_post(sem_t *sem);
功能:使信号量加1,在这个信号量上等待的线程被唤醒
参数:sem:指定的信号量
返回值:0代表成功,-1代表失败,errno被设置
实现生产者和消费者的代码,基于固定大小的环形队列
生产和消费队列共5个,当生产的数字大于消费的数字大于等于5时,等待消费,直到消费时,才开始生产
vi sem_cilcle.c
1 #include<stdio.h>
2 #include<semaphore.h>
3 #include<pthread.h>
4 #define NUM 5
5 int queue[NUM];//环形队列
6 sem_t b_number,p_number;
7 //生产者
8 void *producer(void *arg){
9 int in=0;
10 while(1){
11 sem_wait(&b_number);
12 queue[in]=rand()%1000+1;
13 printf("producer %d\n",queue[in]);
14 sem_post(&p_number);
15 in=(in+1)%NUM;
16 sleep(rand()%2);
17 }
18 }
19 //消费者
20 void *consumer(void *arg){
21 int c=0;
22 while(1){
23 sem_wait(&p_number);
24 printf("consumer%d\n",queue[c]);
25 queue[c]=0;
26 sem_post(&b_number);
27 c=(c+1)%NUM;
28 sleep(rand()%8);
29 }
30 }
31 int main(void){
32 pthread_t pid,cid;
33 //初始化信号量
34 sem_init(&b_number,0,NUM);
35 sem_init(&p_number,0,0);
36 //创建两个线程
37 pthread_create(&cid,NULL,consumer,NULL);
38 pthread_create(&pid,NULL,producer,NULL);
39 //等待线程的结束
40 pthread_join(cid,NULL);
41 pthread_join(pid,NULL);
42 //销毁信号量
43 sem_destroy(&b_number);
44 sem_destroy(&p_number);
45 return 0;
46 }
tarena@tarena-virtual-machine:~/day35$gcc sem_circle.c -lpthread -o sem
tarena@tarena-virtual-machine:~/day35$./sem
producer 384
producer 778
consumer 384
producer 336
producer 493
producer 85
consumer 414
consumer 981
二、 信号量集semaphore
消息队列
共享内存
信号量:
信号量与其它几种IPC机制(管道、共享内存和消息队列)都不一样,它的目的不是在进程之间搭建数据流通的桥梁,而是提供一个可为多个进程共同访问计数器,实时跟踪可用资源的数量,以解决多个用户分享有限资源时的竞争与冲突问题
ftok(2)
semget(2)
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
int semget(key_tkey, int nsems, int semflg);
功能:获取一个跟key值相关的信号量的id
参数:
key:ftok(2)产生的键值
nsems:要创建的信号集包含的信号的个数
semflg:IPC_CREAT
返回值:
-1失败 返回信号量集的id
信号量的操作:
semop(2)
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
int semop(intsemid, struct sembuf *sops, unsigned nsops);
功能:信号量集的操作
参数:
semid:semget(2)的返回值,在这个信号量集上执行操作
sops:指向了进行操作的结构体的数组
noops:要操作的信号的个数
struct sops{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
}
sem_num:信号量在信号量集中的下标索引
sem_op:每个信号量的操作类型
sem_op>0:给信号量加上sem_op值
sem_op=0:如果设置了IPC_NOWAIT,马上返回,错误设置成EAGAIN,没有设置。进程进入睡眠状态,直到信号量为0
sem_op<0:给信号量加上sem_op值,表示进程控制资源
sem_flg:IPC_NOWAIT或者IPC_SEM
返回值:
0成功 -1失败,errno被设置
semctl(2)
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
int semctl(intsemid, int semnum, int cmd, ...);
参数:
semid:
semnum:在集合中的下标
cmd:指明控制操作的类型
union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
};
举例:server.c
Client
重点:内存的管理
进程的管理
线程的管理
信号管理
文件管理
文件系统管理
网络通讯