initializecriticalsection(initializecriticalsection函数)居然可以这样
一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个进程,进程的执行过程不是一条线的,而是多条线共同完成的。 继承 Thread 类
一、线程与进程的区别?1、 线程是进程的一部分,所以线程有的时候被称为是轻权进程或者轻量级进程2、 一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个进程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。
3、 系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源那就是说,出了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。
4、 与进程的控制表PCB相似,线程也有自己的控制表TCB,但是TCB中所保存的线程状态比PCB表中少多了5、 进程是系统所有资源分配时候的一个基本单位,拥有一个完整的虚拟空间地址,并不依赖线程而独立存在。
二、多线程有几种实现方法,都是什么?1. 继承 Thread 类2. 实现 Runnable 接口再 new Thread(YourRunnableOjbect) 三、多线程同步和互斥有几种实现方法,都是什么?
线程间的同步方法大体可分为两类:用户模式和内核模式顾名思义,内核模式就是指利用系统内核对象的单一性来进行同步,使用时需要切换内核态与用户态,而用户模式就是不需要切换到内核态,只在用户态完成操作用户模式下的方法有:原子操作(例如一个单一的全局变量),临界区。
内核模式下的方法有:事件,信号量,互斥量四、编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。
#include#include#include#include#include//#define DEBUG 1
#define NUM 3int n=0; pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER;//互斥量pthread_cond_t qready=PTHREAD_COND_INITIALIZER;
//条件变量void * thread_func(void *arg){ int param=(int)arg; char c=A+param; int ret,i=0; for (; i < 10; i++) { pthread_mutex_lock(&mylock);
while (param != n) { #ifdef DEBUGprintf("thread %d waiting\n", param); #endif ret = pthread_cond_wait(&qready, &mylock);
if (ret == 0) { #ifdef DEBUGprintf("thread %d wait success\n", param); #endif } else { #ifdef DEBUG printf
("thread %d wait failed:%s\n", param, strerror(ret)); #endif } } // printf("%d ",param+1);printf("%c "
,c); n=(n+1)%NUM; pthread_mutex_unlock(&mylock); pthread_cond_broadcast(&qready); } return (void *)0; }
intmain(int argc, char** argv){ int i=0,err; pthread_t tid[NUM]; void *tret; for(;i
NULL,thread_func,(void *)i); if(err!=0) { printf("thread_create error:%s\n",strerror(err)); exit(-1); } }
for (i = 0; i < NUM; i++) { err = pthread_join(tid[i], &tret); if (err != 0) { printf("can not join with thread %d:%s\n"
, i,strerror(err)); exit(-1); } } printf("\n"); return0; }运行结果:
需要C/C++ Linux高级服务器架构师学习资料后台私信“资料”(包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等)
五、生产者消费者问题:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,所有生产者和消费者都是异步方式运行的,但它们必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经装满产品且尚未被取走的缓冲区中投放产品。
方法一,采用互斥量来实现生产者和消费者的同步。流程图如下所示:
生产者:对互斥量加锁判断缓冲区是否已满,如满,则跳到步骤4放入产品解锁互斥量,此时一个循环完成,进入下一循环消费者流程图类似与生产者流程图代码如下:#include #include。
#include #include #define NUMS 10 //表示生产,消费的次数 #define CAPACITY 5
//定义缓冲区最大值 int capacity = 0; //当前缓冲区的产品个数 pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;//互斥量
void *produce(void *args){ int i = 0; for (; i < NUMS; ) { pthread_mutex_lock(&mylock);
//加锁 if (capacity >= CAPACITY) //当前产品个数大于等于缓冲区最大值,则不把产品放入缓冲区 { printf("缓冲区已满,无法放入产品\n"。
); } else {//将产品放入缓冲区 ++capacity; printf("生产者存入一个产品, 缓冲区大小为:%d\n"
, capacity); i++; } pthread_mutex_unlock(&mylock); } return
((void *) 0); } void * consume(void *args){ int i = 0; for (; i < NUMS; ) { pthread_mutex_lock(&mylock);
if (capacity > 0) { --capacity; printf("消费者消耗一个产品,缓冲区大小为:%d\n"
, capacity); i++; } else { printf("缓冲区已空,无法消耗产品\n"); } pthread_mutex_unlock(&mylock); }
return ((void *) 0); } intmain(int argc, char** argv){ int err; pthread_t produce_tid, consume_tid;
void *ret; err = pthread_create(&produce_tid, NULL, produce, NULL);//创建线程 if (err != 0) {
printf("线程创建失败:%s\n", strerror(err)); exit(-1); } err = pthread_create(&consume_tid,
NULL, consume, NULL); if (err != 0) { printf("线程创建失败:%s\n", strerror(err));
exit(-1); } err = pthread_join(produce_tid, &ret);//主线程等到子线程退出 if (err != 0) {
printf("生产着线程分解失败:%s\n", strerror(err)); exit(-1); } err = pthread_join(consume_tid, &ret);
if (err != 0) { printf("消费者线程分解失败:%s\n", strerror(err)); exit(-1); }
return (EXIT_SUCCESS); } 执行结果:
结果满足题意但是这存在一个问题,极端情况下,生产者每次都加锁成功,那缓冲区会满,产品无法放入缓冲区消费者会被饿死,因为他一直无法获得互斥量方法二,解决了导致某一方饿死的可能性update: 在第一种方法中,当缓冲区满时,让生产者睡眠;当缓冲区空,让消费者睡眠。
这样也能解决某一方老是加锁成功方法二:采用两个互斥量来完成 流程图如下:
运行截图:
上代码:/* * File: main.c * Author: root * * Created on 2012年5月22日, 上午9:35 */#include
#include #include #include #define NUMS 10 //表示生产,消费的次数 #define CAPACITY 5
//定义缓冲区最大值 int capacity = 0; //当前缓冲区的产品个数 pthread_mutex_t mylockA=PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t
mylockB=PTHREAD_MUTEX_INITIALIZER; void *produce(void *args){ int i = 0,err; for (; i < NUMS; ) { pthread_mutex_lock(&mylockA);
//加锁 if (capacity >= CAPACITY) //当前产品个数大于等于缓冲区最大值,则不把产品放入缓冲区 { printf("缓冲区已满,无法放入产品\n"。
); } else {//将产品放入缓冲区 ++capacity; printf("生产者存入一个产品, 产品个数:%d\n"
, capacity); i++; } err=pthread_mutex_unlock(&mylockB); }
return ((void *) 0); } void * consume(void *args){ int i = 0; for (; i < NUMS; ) { pthread_mutex_lock(&mylockB);
if (capacity > 0) { --capacity; printf("消费者消耗一个产品,产品个数:%d\n", capacity); i++; }
else { printf("缓冲区已空,无法消耗产品\n"); } pthread_mutex_unlock(&mylockA); }
return ((void *) 0); } intmain(int argc, char** argv){ int err; pthread_t produce_tid, consume_tid;
void *ret; if(capacity==0) pthread_mutex_lock(&mylockB); elseif(capacity==CAPACITY) pthread_mutex_lock(&mylockA); err = pthread_create(&produce_tid,
NULL, produce, NULL);//创建线程 if (err != 0) { printf("线程创建失败:%s\n", strerror(err));
exit(-1); } err = pthread_create(&consume_tid, NULL, consume, NULL); if (err != 0) {
printf("线程创建失败:%s\n", strerror(err)); exit(-1); } err = pthread_join(produce_tid, &ret);
//主线程等到子线程退出 if (err != 0) { printf("生产着线程分解失败:%s\n", strerror(err)); exit
(-1); } err = pthread_join(consume_tid, &ret); if (err != 0) { printf
("消费者线程分解失败:%s\n", strerror(err)); exit(-1); } return (EXIT_SUCCESS); } 六、有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者读时写者也不能写。
分析:首先来找找哪些是属于“等待”情况第一、写者要等到没有读者时才能去写文件第二、所有读者要等待写者完成写文件后才能去读文件找完“等待”情况后,再看看有没有要互斥访问的资源由于只有一个写者而读者们是可以共享的读文件,所以按题目要求并没有需要互斥访问的资源。
代码如下:#include “stdafx.h” #include “stdio.h” #include “stdlib.h” #include #include
#include #include #include usingnamespacestd; //读者与写者问题 #include
#include #include //设置控制台输出颜色 BOOL SetConsoleColor(WORD wAttributes)
{ HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); if (hConsole == INVALID_HANDLE_VALUE)
return FALSE; return SetConsoleTextAttribute(hConsole, wAttributes); } constint READER_NUM =
5; //读者个数 //关键段和事件 CRITICAL_SECTION g_cs, g_cs_writer_count; HANDLE g_hEventWriter, g_hEventNoReader;
int g_nReaderCount; //读者线程输出函数(变参函数的实现) voidReaderPrintf(char *pszFormat, …){ va_list pArgList; va_start(pArgList, pszFormat); EnterCriticalSection(&g_cs);
vfprintf(stdout, pszFormat, pArgList); LeaveCriticalSection(&g_cs); va_end(pArgList); }
//读者线程函数 unsignedint __stdcall ReaderThreadFun(PVOID pM){ ReaderPrintf(“ 编号为%d的读者进入等待中…\n”, GetCurrentThreadId());
//等待写者完成 WaitForSingleObject(g_hEventWriter, INFINITE); //读者个数增加 EnterCriticalSection(&g_cs_writer_count); g_nReaderCount++;
if (g_nReaderCount == 1) ResetEvent(g_hEventNoReader); LeaveCriticalSection(&g_cs_writer_count);
//读取文件 ReaderPrintf(“编号为%d的读者开始读取文件…\n”, GetCurrentThreadId()); Sleep(rand() % 100);
//结束阅读,读者个数减小,空位增加 ReaderPrintf(“ 编号为%d的读者结束读取文件\n”, GetCurrentThreadId()); //读者个数减少
EnterCriticalSection(&g_cs_writer_count); g_nReaderCount–; if (g_nReaderCount == 0) SetEvent(g_hEventNoReader); LeaveCriticalSection(&g_cs_writer_count);
return0; } //写者线程输出函数 voidWriterPrintf(char *pszStr){ EnterCriticalSection(&g_cs); SetConsoleColor(FOREGROUND_GREEN);
printf(“ %s\n”, pszStr); SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); LeaveCriticalSection(&g_cs); }
//写者线程函数 unsignedint __stdcall WriterThreadFun(PVOID pM){ WriterPrintf(“写者线程进入等待中…”); //等待读文件的读者为零
WaitForSingleObject(g_hEventNoReader, INFINITE); //标记写者正在写文件 ResetEvent(g_hEventWriter);
//写文件 WriterPrintf(“ 写者开始写文件…..”); Sleep(rand() % 100); WriterPrintf(“ 写者结束写文件”);
//标记写者结束写文件 SetEvent(g_hEventWriter); return0; } intmain(){ printf(“ 读者写者问题\n”);
printf(“ – by MoreWindows( http://blog.csdn.net/MoreWindows ) –\n\n”); //初始化事件和信号量 InitializeCriticalSection(&g_cs); InitializeCriticalSection(&g_cs_writer_count);
//手动置位,初始已触发 g_hEventWriter = CreateEvent(NULL, TRUE, TRUE, NULL); g_hEventNoReader = CreateEvent(
NULL, FALSE, TRUE, NULL); g_nReaderCount = 0; int i; HANDLE hThread[READER_NUM +
1]; //先启动二个读者线程 for (i = 1; i <= 2; i++) hThread[i] = (HANDLE)_beginthreadex(NULL, 0
, ReaderThreadFun, NULL, 0, NULL); //启动写者线程 hThread[0] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun,
NULL, 0, NULL); Sleep(50); //最后启动其它读者结程 for ( ; i <= READER_NUM; i++) hThread[i] = (HANDLE)_beginthreadex(
NULL, 0, ReaderThreadFun, NULL, 0, NULL); WaitForMultipleObjects(READER_NUM + 1, hThread, TRUE, INFINITE);
for (i = 0; i < READER_NUM + 1; i++) CloseHandle(hThread[i]); //销毁事件和信号量 CloseHandle(g_hEventWriter); CloseHandle(g_hEventNoReader); DeleteCriticalSection(&g_cs); DeleteCriticalSection(&g_cs_writer_count);
return0; } 七、编写程序完成如下功能:1)有一int型全局变量g_Flag初始值为02) 在主线称中起动线程1,打印“this is thread1”,并将g_Flag设置为13) 在主线
称中启动线程2,打印“this is thread2”,并将g_Flag设置为24) 线程序1需要在线程2退出后才能退出5) 主线程在检测到g_Flag从1变为2,或者从2变为1的时候退出atomic<
int> flag(0); voidworker1(future fut){//线程1 printf("this is thread1\n"); flag = 1; fut.get();
//线程1阻塞至线程2设置共享状态 get等待异步操作结束并返回结果printf("thread1 exit\n"); } voidworker2(promise prom){//线程2
printf("this is thread2\n");//C++11的线程输出cout没有boost的好,还是会出现乱序,所以采用printf,有点不爽 flag = 2; prom.set_value(
10);//线程2设置了共享状态后,线程1才会被唤醒 printf("thread2 exit\n"); } //利用promise future来控制线程退出的次序intmain(){ promise<
int> prom; future fut = prom.get_future(); thread one(worker1, move(fut));//注意future和promise不允许拷贝,但是具备move语义
thread two(worker2, move(prom)); while (flag.load() == 0); ///将本线程从调用线程中分离出来,允许本线程独立执行 one.detach(); two.detach();
//exit(1);//主线程到这里退出 printf("main thread exit\n"); system("pause"); return0; }
- 标签:
- 编辑:李松一
- 相关文章
-
为什么都不建议去邮政银行(为什么都不建议去邮政银行存款)居然可以这样
邮储银行确实是一家值得关注的银行,其零售端数据让人浮想联翩:4万家网点,6亿个客户,10万亿存款,管理个人客户资产高达12.53万亿元,邮储…
-
棉签冰块夹子扩张器是干嘛用的(棉签冰块夹子扩张器是干嘛用的h)快来看
6月16日15时许,宝鸡市眉县河堤南路高架桥向西一公里处发生一起车祸,一人被卡车内,消防部门接到报警后立即出动2车10人前往处置。…
- 第二季好声音四强(第三季好声音那英组四强全是)原创
- 女人手表钢表带(劳力士售后服务中心)这都可以?
- pps屠龙传说(pps屠龙传说捡取过滤)学到了
- 逆天邪神提前看大结局(逆天邪神提前看大结局修罗武神)怎么可以错过
- 养父40(养父40集剧情介绍)奔走相告