济南大型网站建设,优质网站建设价格,搜索关键词分析,一个网站源代码概多大一、Xmind整理#xff1a;
二、课上练习#xff1a;
练习1#xff1a;创建两个线程#xff1a;其中一个线程拷贝前半部分#xff0c;另一个线程拷贝后半部分。 只允许开一份资源#xff0c;且用互斥锁方式实现。 提示#xff1a;找临界区---找临界资源。
#includ…一、Xmind整理
二、课上练习
练习1创建两个线程其中一个线程拷贝前半部分另一个线程拷贝后半部分。 只允许开一份资源且用互斥锁方式实现。 提示找临界区---找临界资源。
#include stdio.h
#include sys/stat.h
#include sys/types.h
#include fcntl.h
#include unistd.h
#include head.h
#include pthread.h//定义一个结构体传入到线程中
struct Msg
{int fd_r;int fd_w;off_t size;
};//定义互斥锁
pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER;//拷贝前半部分
void* callBack1(void* arg) //void* arg fileinfo
{int fd_r ((struct Msg*)arg)-fd_r;int fd_w ((struct Msg*)arg)-fd_w;off_t size ((struct Msg*)arg)-size;//修改文件偏移量到文件开头位置off_t offset 0;char c 0;for(int i 0; isize/2; i){/*********临界区****************/pthread_mutex_lock(mutex); //上锁lseek(fd_r, offset, SEEK_SET);lseek(fd_w, offset, SEEK_SET);read(fd_r, c, 1);write(fd_w, c, 1);offset lseek(fd_r, 0, SEEK_CUR);pthread_mutex_unlock(mutex); //解锁/*********临界区****************/}printf(前半部分拷贝完毕\n);pthread_exit(NULL);
}//拷贝后半部分
void* callBack2(void* arg) //void* arg fileinfo
{int fd_r ((struct Msg*)arg)-fd_r;int fd_w ((struct Msg*)arg)-fd_w;off_t size ((struct Msg*)arg)-size;//修改文件偏移量到sizee/2位置off_t offset size/2;char c 0;for(int i size/2; isize; i){/*********临界区****************/pthread_mutex_lock(mutex); //上锁lseek(fd_r, offset, SEEK_SET);lseek(fd_w, offset, SEEK_SET);read(fd_r, c, 1);write(fd_w, c, 1);offset lseek(fd_r, 0, SEEK_CUR);pthread_mutex_unlock(mutex); //解锁/*********临界区****************/}printf(后半部分拷贝完毕\n);pthread_exit(NULL);
}int main(int argc, const char *argv[])
{//以读的方式打开源文件int fd_r open(./1.png, O_RDONLY);if(fd_r 0){ERR_MSG(open);return -1;}//以写的方式打开目标文件int fd_w open(./copy.png, O_WRONLY|O_CREAT|O_TRUNC, 0664);if(fd_w 0){ERR_MSG(open);return -1;}off_t size lseek(fd_r, 0, SEEK_END);struct Msg fileinfo;fileinfo.fd_r fd_r;fileinfo.fd_w fd_w;fileinfo.size size;//创建一个线程pthread_t tid1, tid2;if(pthread_create(tid1, NULL, callBack1, fileinfo) ! 0){fprintf(stderr, pthread_create failed __%d__\n, __LINE__);return -1;} if(pthread_create(tid2, NULL, callBack2, fileinfo) ! 0){fprintf(stderr, pthread_create failed __%d__\n, __LINE__);return -1;}//阻塞等待分支线程退出pthread_join(tid2, NULL);pthread_join(tid1, NULL);//销毁互斥锁pthread_mutex_destroy(mutex);//关闭文件close(fd_r);close(fd_w);return 0;
}练习2sem_init
功能创建并初始化信号量
原型:
#include semaphore.h
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数
sem_t *sem存储申请后的信号量;
int pshared共享标识
0信号量用于同一个进程下的线程的同步互斥
非0用于进程间的同步互斥机制;
unsigned int value信号量的初始值;
返回值
成功返回0
失败返回-1更新errno;
练习3sem_waitP操作
功能申请信号量若申请成功信号量的值-1
当信号量的值大于0则申请信号量成功信号量的值-1
当信号量的值等于0则申请信号量操作会阻塞线程进入休眠等待信号量的值大于0解除阻塞。
原型:
#include semaphore.h
int sem_wait(sem_t *sem);
参数
sem_t *sem指定要操作哪个信号灯;
返回值
成功返回0;
失败返回-1更新errno;
练习4sem_postV操作
功能释放信号灯的值
原型:
#include semaphore.h
int sem_post(sem_t *sem);
返回值 成功返回0;失败返回-1更新errno;
练习5sem_destroy
原型:
#include semaphore.h
int sem_destroy(sem_t *sem);
小练
#include stdio.h
#include string.h
#include stdlib.h
#include head.h
#include pthread.h
#include semaphore.h
void* CallBack(void* arg) //void* arg sem;
{sleep(3);//V操作if(sem_post((sem_t*)arg)0){perror(sem_post);return NULL;}printf(V operation success __%d__\n,__LINE__);pthread_exit(NULL);
}int main(int argc, const char *argv[])
{sem_t sem;if(sem_init(sem,0,2)0){perror(sem_init);return -1;}printf(sem_init success __%d__\n,__LINE__);//创建一个线程3s后V一次pthread_t tid;if(pthread_create(tid,NULL,CallBack,(void*)sem) ! 0){fprintf(stderr,pthread_create failed:__%d__\n,__LINE__);return -1;}//P操作 if(sem_wait(sem)0){perror(sem_wait);return -1;}printf(P operation success __%d__\n,__LINE__);//P操作if(sem_wait(sem)0){perror(sem_wait);return -1;}printf(P operation success __%d__\n,__LINE__);//P操作if(sem_wait(sem)0){perror(sem_wait);return -1;}printf(P operation success __%d__\n,__LINE__);pthread_join(tid,NULL);sem_destroy(sem);return 0;
}练习6先打印1234567后打印7654321
#include stdio.h
#include string.h
#include stdlib.h
#include head.h
#include pthread.h
#include semaphore.h
//临界资源
char buf[]1234567;void* CallBack1(void* arg)
{while(1){/**********临界区*********///p操作if(sem_wait((sem_t*)arg)0){perror(sem_wait);return NULL;}printf(%s\n,buf);//v操作if(sem_post((sem_t*)arg)0){perror(sem_post);return NULL;}/**********临界区*********/}pthread_exit(NULL);
}
void* CallBack2(void* arg)
{char tmp0;while(1){/**********临界区*********///p操作if(sem_wait((sem_t*)arg)0){perror(sem_wait);return NULL;}for(int i0;istrlen(buf)/2;i){tmpbuf[i];buf[i]buf[strlen(buf)-1-i];buf[strlen(buf)-1-i]tmp;}//v操作if(sem_post((sem_t*)arg)0){perror(sem_post);return NULL;}/**********临界区*********/}pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{sem_t sem;if(sem_init(sem,0,1)0){perror(sem_init);return -1;}printf(sem_init success __%d__\n,__LINE__);//创建线程pthread_t tid1,tid2;if(pthread_create(tid1,NULL,CallBack1,(void*)sem) ! 0){fprintf(stderr,pthread_create failed:__%d__\n,__LINE__);return -1;}pthread_detach(tid1); //分离线程1if(pthread_create(tid2,NULL,CallBack2,(void*)sem) ! 0){fprintf(stderr,pthread_create failed:__%d__\n,__LINE__);return -1;}pthread_join(tid2,NULL); //阻塞等待线程2退出//销毁信号量sem_destroy(sem);return 0;
} 练习7pthread_cond_init
功能创建并初始化一个条件变量唤醒条件
原型
#include pthread.h
pthread_cond_t cond PTHREAD_COND_INITIALIZER;
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
参数
pthread_cond_t *cond指定存储创建并初始化后的条件变量;
pthread_condattr_t *cond_attr条件变量属性设置条件变量适用于进程间还是线程间的同步互斥。填NULL默认属性用于线程
返回值
成功返回0;
失败返回非0没有说更新errno所以不要用perror打印错误。
练习8pthread_cond_wait
功能阻塞函数让当前线程进入休眠阶段并设置一个条件变量等待被唤醒
原型
#include pthread.h
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
参数
pthread_cond_t *cond指定条件变量; 我们一般称 该线程睡在该条件变量上;
pthread_mutex_t *mutex指定要解开的互斥锁
返回值
成功返回0;
失败返回非0没有说更新errno所以不要用perror打印错误。 函数步骤 1.解开互斥锁同时让当前线程进入休眠阶段等待被唤醒。原子操作原子从操作是指不会被调度机制打断的操作 2.等待被指定条件变量唤醒 3.当其他线程pthread_cond_signal的时候线程会从cond_wait队列移动到mutex_lock队列中且signal计数器1线程尝试上锁 4.若上锁成功则线程完全被唤醒此时线程会从当前位置继续往后执行且signal计数器-1; 5.若上锁失败则线程会重新回到cond_wait队列上继续休眠等待下一次唤醒。 ps如果上述不能理解则简化版pthread_cond_signal肯定会随机唤醒一个睡在cond上的线程。 练习9pthread_conde_signal
功能通过指定条件变量唤醒睡在该条件变量上的某个线程
原型
#include pthread.h
int pthread_cond_signal(pthread_cond_t *cond);
参数
pthread_cond_t *cond唤醒睡在哪个条件变量上的线程;
返回值
成功返回0;
失败返回非0没有说更新errno所以不要用perror打印错误。
练习10pthread_cond_destroy
功能销毁条件变量
原型
#include pthread.h
int pthread_cond_destroy(pthread_cond_t *cond);
小练1
#include stdio.h
#include string.h
#include stdlib.h
#include head.h
#include pthread.h
#include semaphore.h
//临界资源
char buf[]1234567;
//互斥锁 方式2
pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER;
//条件变量创建 方式2
pthread_cond_t cond PTHREAD_COND_INITIALIZER;
int flag 0; //限制访问时机
void* CallBack1(void* arg)
{while(1){/**********临界区*********///上锁pthread_mutex_lock(mutex);if(flag !0){//让线程进入休眠等待阶段同时解开互斥锁//设置一个唤醒条件pthread_cond_wait(cond,mutex);//当被唤醒的时候会立即尝试上锁//上锁成功则唤醒成功则从当前位置继续往后执行//上锁失败则重新回到cond上继续休眠等待下一次唤醒}printf(%s\n,buf);flag 1;//唤醒睡在cond上的线程pthread_cond_signal(cond);//目前大家暂时理解为只要唤醒成功了对方线程肯定能上锁成功//解锁pthread_mutex_unlock(mutex);/**********临界区*********/}pthread_exit(NULL);
}
void* CallBack2(void* arg)
{char* start,*end;char tmp0;while(1){/**********临界区*********///上锁pthread_mutex_lock(mutex);if(flag !1){//让线程进入休眠等待阶段同时解开互斥锁//设置一个唤醒条件pthread_cond_wait(cond,mutex);//当被唤醒的时候会立即尝试上锁//上锁成功则唤醒成功则从当前位置继续往后执行//上锁失败则重新回到cond上继续休眠等待下一次唤醒}start buf;end bufstrlen(buf)-1;while(start end){tmp *start;*start *end;*end tmp;start;end--;}flag 0;//唤醒睡在cond上的线程pthread_cond_signal(cond);//目前大家暂时理解为只要唤醒成功了对方线程肯定能上锁成功//解锁pthread_mutex_unlock(mutex);/**********临界区*********/}pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{/*//创建一个条件变量 方式1if(pthread_cond_init(cond,NULL)! 0){fprintf(stderr,pthread_cond_init failed __%d__\n,__LINE__);return -1;}*///创建线程pthread_t tid1,tid2;if(pthread_create(tid1,NULL,CallBack1,NULL) ! 0){fprintf(stderr,pthread_create failed:__%d__\n,__LINE__);return -1;}pthread_detach(tid1); //分离线程1if(pthread_create(tid2,NULL,CallBack2,NULL) ! 0){fprintf(stderr,pthread_create failed:__%d__\n,__LINE__);return -1;}pthread_join(tid2,NULL); //阻塞等待线程2退出//销毁互斥锁pthread_mutex_destroy(mutex);pthread_cond_destroy(cond);return 0;
}小练2创建三个线程 id号为ABC要求三个线程循环打印自己的ID号运行顺序为 ABCABC......
#include stdio.h
#include string.h
#include stdlib.h
#include head.h
#include pthread.h
#include semaphore.h//互斥锁 方式2
pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER;
//条件变量创建 方式2
pthread_cond_t cond1 PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 PTHREAD_COND_INITIALIZER;
pthread_cond_t cond3 PTHREAD_COND_INITIALIZER;int flag 1; //1:A 2:B 3:Cvoid* A(void* arg)
{while(1){//上锁pthread_mutex_lock(mutex);if(flag ! 1){pthread_cond_wait(cond1,mutex); }printf(A);flag 2 ;pthread_cond_signal(cond2);//解锁 pthread_mutex_unlock(mutex);}pthread_exit(NULL);
}
void* B(void* arg)
{while(1){//上锁pthread_mutex_lock(mutex);if(flag ! 2){pthread_cond_wait(cond2,mutex);}printf(B);flag 3 ;pthread_cond_signal(cond3);//解锁 pthread_mutex_unlock(mutex);}pthread_exit(NULL);
}
void* C(void* arg)
{while(1){//上锁pthread_mutex_lock(mutex);if(flag ! 3){pthread_cond_wait(cond3,mutex);}printf(C\n);flag 1 ;pthread_cond_signal(cond1);//解锁 pthread_mutex_unlock(mutex);}pthread_exit(NULL);
}int main(int argc, const char *argv[])
{/*//创建一个条件变量 方式1if(pthread_cond_init(cond,NULL)! 0){fprintf(stderr,pthread_cond_init failed __%d__\n,__LINE__);return -1;}*///创建线程pthread_t tid1,tid2,tid3;if(pthread_create(tid1,NULL,A,NULL) ! 0){fprintf(stderr,pthread_create failed:__%d__\n,__LINE__);return -1;}pthread_detach(tid1); //分离线程1if(pthread_create(tid2,NULL,B,NULL) ! 0){fprintf(stderr,pthread_create failed:__%d__\n,__LINE__);return -1;}pthread_detach(tid2);if(pthread_create(tid3,NULL,C,NULL) ! 0){fprintf(stderr,pthread_create failed:__%d__\n,__LINE__);return -1;}pthread_join(tid3,NULL); //阻塞等待线程2退出//销毁互斥锁pthread_mutex_destroy(mutex);pthread_cond_destroy(cond1);pthread_cond_destroy(cond2);pthread_cond_destroy(cond3);return 0;
}三、课后作业
1.使用信号量的方式实现将倒置以及打印的那道题目在第一题的基础上加上一个需求要求打印倒置线程顺序执行。出现的现象为先打印1234567后打印7654321不使用flag
#include stdio.h
#include pthread.h
#include string.h
#include semaphore.h//临界资源
char buf[] 1234567;//信号量
sem_t sem1;
sem_t sem2;void* callBack1(void* arg)
{while(1){sem_wait(sem1);fprintf(stderr,%s\n,buf);sem_post(sem2);}
}
void* callBack2(void* arg)
{char tmp 0;while(1){sem_wait(sem2);for(int i0; istrlen(buf)/2; i){tmp buf[i];buf[i] buf[strlen(buf)-1-i];buf[strlen(buf)-1-i] tmp;}sem_post(sem1);}
}int main(int argc, const char *argv[])
{//申请信号量if(sem_init(sem1, 0, 1) 0){perror(sem_init);return -1;}if(sem_init(sem2,0,0) 0){perror(sem_init);return -1;}pthread_t tid1, tid2;if(pthread_create(tid1, NULL, callBack1, NULL) ! 0){fprintf(stderr, pthread_create failed __%d__\n, __LINE__);return -1;}pthread_detach(tid1); //分离线程1if(pthread_create(tid2, NULL, callBack2, NULL) ! 0){fprintf(stderr, pthread_create failed __%d__\n, __LINE__);return -1;}pthread_join(tid2, NULL); //阻塞等待线程2退出//销毁信号量sem_destroy(sem1);sem_destroy(sem2);return 0;
} 2.创建两个线程其中一个线程读取文件中的数据另外一个线程将读取到的内容打印到终端上类似实现cat一个文件。
cat数据完毕后要结束两个线程。
提示先读数据读到数据后将数据打印到终端上。
#include stdio.h
#include head.h
#include pthread.h
#include semaphore.hint fd;
char c;
sem_t sem1;
sem_t sem2;
int res -1;void *callBack1(void *arg)
{while(1){sem_wait(sem1);if(read(fd,c,1) 0){res close(fd);sem_post(sem2);break;}sem_post(sem2);} printf(线程1\n);pthread_exit(NULL);
}
void *callBack2(void *arg)
{while(1){sem_wait(sem2);if(res 0)break;write(1,c,1);sem_post(sem1);}printf(线程2\n);pthread_exit(NULL);
}int main(int argc, const char *argv[])
{fd open(1.txt,O_RDONLY);if(fd 0){perror(open);return -1;}if(sem_init(sem1,0,1) 0){perror(sem_init);return -1;}if(sem_init(sem2,0,0) 0){perror(sem_init);return -1;}pthread_t tid1,tid2;if(pthread_create(tid1,NULL,callBack1,NULL) 0){fprintf(stderr,pthread_create falied __%d__,__LINE__);return -1;}if(pthread_create(tid2,NULL,callBack2,NULL) 0){fprintf(stderr,pthread_create falied __%d__,__LINE__);return -1;}pthread_join(tid1,NULL);pthread_join(tid2,NULL);//销毁信号量sem_destroy(sem1);sem_destroy(sem2);return 0;
}