- 前言
- 一、理论部分
- 二、实际 *** 作
- 1.创建子进程(fork)条件变量(等出租车,两线程)
- 2.线程池概念和创建使用
- 3.线程间的通信1(无名管道(pipe))
- 4.线程间的通信2(有名管道 (fifo))
- 5.线程间的通信3(共享内存(mmap),用的最多)
- 6.线程间的通信4(信号(signal))
- 7.线程间的通信5(套接字(socket)详情间网络部分)
- 总结
理论部分请见线程篇
无名管道:血缘关系的进程,父子进程间,单工通信
有名管道:任意两个,或者以上的进程通信,单工
共享内存:更方便,不必调用read,write这些。可以直接访问内存的方式访问。
信号通信:信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式
所有信号的产生及处理全部都是由内核完成的
信号的产生:
1 按键产生
2 系统调用函数产生(比如raise, kill)
3 硬件异常
4 命令行产生 (kill)
5 软件条件(比如被0除,访问非法内存等)
信号处理方式:
1 缺省方式
2 忽略信号
3 捕捉信号
套接字法:详情请见网络部分用的最多
二.实际 *** 作 1、条件变量(等出租车,两线程)应用场景:生产者消费者问题,是线程同步的一种手段。
必要性:为了实现等待某个资源,让线程休眠。提高运行效率
#include
#include
#include
#include
pthread_cond_t hasTaxi=PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
struct taxi{
struct taxi *next;
int num;
};
struct taxi *Head=NULL;
void *taxiarv(void *arg){
printf("taxi arrived thread\n");
pthread_detach(pthread_self());
struct taxi *tx;
int i=1;
while(1){
tx = malloc(sizeof(struct taxi));
tx->num = i++;
printf("taxi %d comming\n",tx->num);
pthread_mutex_lock(&lock);
tx->next = Head;
Head = tx;
pthread_cond_signal(&hasTaxi);
//pthread_cond_broadcast(&hasTaxi);
pthread_mutex_unlock(&lock);
sleep(1);
}
pthread_exit(0);
}
void *takeTaxi(void *arg){
printf("take taxi thread\n");
pthread_detach(pthread_self());
struct taxi *tx;
while(1){
pthread_mutex_lock(&lock);
while(Head==NULL)
{
pthread_cond_wait(&hasTaxi,&lock);
}
tx = Head;
Head=tx->next;
printf("%d,Take taxi %d\n",(int)arg,tx->num);
free(tx);
pthread_mutex_unlock(&lock);
}
pthread_exit(0);
}
int main(){
pthread_t tid1,tid2,tid3;
pthread_create(&tid1,NULL,taxiarv,NULL);
// sleep(5);
pthread_create(&tid2,NULL,takeTaxi,(void*)1);
pthread_create(&tid2,NULL,takeTaxi,(void*)2);
pthread_create(&tid3,NULL,takeTaxi,(void*)3);
while(1) {
sleep(1);
}
}
线程池概念和创建使用
概念:
通俗的讲就是一个线程的池子,可以循环的完成任务的一组线程集合
必要性:
我们平时创建一个线程,完成某一个任务,等待线程的退出。但当需要创建大量的线程时,假设T1为创建线程时间,T2为在线程任务执行时间,T3为线程销毁时间,当 T1+T3 > T2,这时候就不划算了,使用线程池可以降低频繁创建和销毁线程所带来的开销,任务处理时间比较短的时候这个好处非常显著。
线程池的基本结构:
1 任务队列,存储需要处理的任务,由工作线程来处理这些任务
2 线程池工作线程,它是任务队列任务的消费者,等待新任务的信号
创建五步走(创建线程池的基本结构,线程池的初始化,线程池添加任务,实现工作线程,线程池的销毁)
#include
#include
#include
#include
#define POOL_NUM 10
typedef struct Task{
void *(*func)(void *arg);
void *arg;
struct Task *next;
}Task;
typedef struct ThreadPool{
pthread_mutex_t taskLock;
pthread_cond_t newTask;
pthread_t tid[POOL_NUM];
Task *queue_head;
int busywork;
}ThreadPool;
ThreadPool *pool;
void *workThread(void *arg){
while(1){
pthread_mutex_lock(&pool->taskLock);
pthread_cond_wait(&pool->newTask,&pool->taskLock);
Task *ptask = pool->queue_head;
pool->queue_head = pool->queue_head->next;
pthread_mutex_unlock(&pool->taskLock);
ptask->func(ptask->arg);
pool->busywork--;
}
}
void *realwork(void *arg){
printf("Finish work %d\n",(int)arg);
}
void pool_add_task(int arg){
Task *newTask;
pthread_mutex_lock(&pool->taskLock);
while(pool->busywork>=POOL_NUM){
pthread_mutex_unlock(&pool->taskLock);
usleep(10000);
pthread_mutex_lock(&pool->taskLock);
}
pthread_mutex_unlock(&pool->taskLock);
newTask = malloc(sizeof(Task));
newTask->func = realwork;
newTask->arg = arg;
pthread_mutex_lock(&pool->taskLock);
Task *member = pool->queue_head;
if(member==NULL){
pool->queue_head = newTask;
}else{
while(member->next!=NULL){
member=member->next;
}
member->next = newTask;
}
pool->busywork++;
pthread_cond_signal(&pool->newTask);
pthread_mutex_unlock(&pool->taskLock);
}
void pool_init(){
pool = malloc(sizeof(ThreadPool));
pthread_mutex_init(&pool->taskLock,NULL);
pthread_cond_init(&pool->newTask,NULL);
pool->queue_head = NULL;
pool->busywork=0;
for(int i=0;itid[i],NULL,workThread,NULL);
}
}
void pool_destory(){
Task *head;
while(pool->queue_head!=NULL){
head = pool->queue_head;
pool->queue_head = pool->queue_head->next;
free(head);
}
pthread_mutex_destroy(&pool->taskLock);
pthread_cond_destroy(&pool->newTask);
free(pool);
}
int main(){
pool_init();
sleep(20);
for(int i=1;i<=20;i++){
pool_add_task(i);
}
sleep(5);
pool_destory();
}
(3)无名管道
- 只能用于亲缘关系的进程间通信(父子进程,兄弟进程)
- 管道通信是单工的,一端读,一端写(程序实现设计好)
- 数据自己读不能自己写
- 管道可以用于大于2个进程共享
#include
#include
#include
int main(){
int pfd[2];
int re;
char buf[20]={0};
pid_t pid;
re = pipe(pfd);
if(re<0){
perror("pipe");
return 0;
}
printf("%d,%d\n",pfd[0],pfd[1]);
pid = fork();
if(pid<0){
perror("fork");
return 0;
}else if(pid>0){
//close(pfd[0]);
while(1){
strcpy(buf,"hhahahahah");
write(pfd[1],buf,strlen(buf));
sleep(1);
}
}else{
close(pfd[1]);
while(1){
re=read(pfd[0],buf,20);
if(re>0){
printf("read pipe=%s\n",buf);
}
}
}
}
一个父进程读,两个子进程写入(时间错开一点点)
#include
#include
#include
int main(){
int pfd[2];
int i;
int re;
char buf[40]={0};
pid_t pid;
re = pipe(pfd);
if(re<0){
perror("pipe");
return 0;
}
printf("%d,%d\n",pfd[0],pfd[1]);
for(i=0;i<2;i++){
pid = fork();
if(pid<0){
perror("fork");
return 0;
}else if(pid>0){
}else{
break;
}
}
if(i==2){
close(pfd[1]);
while(1){
memset(buf,0,40);
re=read(pfd[0],buf,40);
if(re>0){
printf("%s\n",buf);
}
}
return 0;
}
if(i==1){
close(pfd[0]);
while(1){
strcpy(buf,"this is 2 process");
write(pfd[1],buf,strlen(buf));
usleep(930000);
}
return 0;
}
if(i==0){
close(pfd[0]);
while(1){
strcpy(buf,"this is 1 process");
write(pfd[1],buf,strlen(buf));
sleep(1);
}
return 0;
}
}
(4) 有名管道(命名管道,FIFO,先进先出)
有名管道可以使非亲缘的两个进程互相通信
通过路径名来 *** 作,在文件系统中可见,但内容存放在内存中
文件IO来 *** 作有名管道(创建是创建文件)
不支持leek *** 作
单工读写
两个文件(一个读,,一个写)
#include
#include
#include
#include
#include
#include
#include
int main(){
int re;
int fd;
char buf[32];
re = mkfifo("/myfifo",0666);
if(re<0){
perror("mkfifo");
//return 0;
}
fd = open("/myfifo",O_WRONLY|O_NONBLOCK);
if(fd<0){
perror("open");
return 0;
}
printf("after open\n");
while(1){
fgets(buf,32,stdin);
write(fd,buf,strlen(buf));
}
}
#include
#include
#include
#include
#include
#include
#include
int main(){
int re;
int fd;
char buf[32];
/*
re = mkfifo("/myfifo",0666);
if(re<0){
perror("mkfifo");
return 0;
}
*/
fd = open("/myfifo",O_RDONLY);
if(fd<0){
perror("open");
return 0;
}
printf("after open\n");
while(1){
re=read(fd,buf,32);
if(re>0){
printf("read fifo=%s\n",buf);
}else if(re==0){
exit(0);
}
}
}
(5)进程的通信--共享内存(mmap)
•
实现了用户空间和内核空间的高效交互方式(mmap)
(两个程序一个写,一个读)
#include
#include
#include
#include
#include
#include
#include
#include
int main(){
void *addr;
int fd;
fd =open("test",O_RDWR);
if(fd<0){
perror("open");
return 0;
}
int len = lseek(fd,0,SEEK_END);
addr = mmap(NULL,2048, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(addr == MAP_FAILED){
perror("mmap");
return 0;
}
close(fd);
// memcpy((addr),"99999999999999",15);
while(1){
printf("read=%s\n",(char*)(addr));
sleep(1);
}
}
#include
#include
#include
#include
#include
#include
#include
#include
int main(){
void *addr;
int fd;
fd =open("test",O_RDWR);
if(fd<0){
perror("open");
return 0;
}
int len = lseek(fd,0,SEEK_END);
addr = mmap(NULL,2048, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(addr == MAP_FAILED){
perror("mmap");
return 0;
}
close(fd);
int i=0;
while(i<2048){
memcpy((addr+i),"a",1);
i++;
sleep(1);
}
// printf("read=%s\n",(char*)(addr));
}
父子进程间通信
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(){
void *addr;
addr = mmap(NULL,2048, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if(addr == MAP_FAILED){
perror("mmap");
return 0;
}
pid_t pid;
pid = fork();
if(pid<0){
perror("fork");
return 0;
}
else if(pid>0){
memcpy(addr,"1234567890",10);
wait(NULL);
}else {
sleep(1);
printf("read father val=%s\n",(char *)addr);
}
munmap(addr,2048); //释放内存
}
(6)信号机制(中断类似)
抱歉,暂时不太想写,等日后补全。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)