分类 多线程 下的文章

线程间数据传递-多线程处理队列CXMulThreadQueue(IOCP实现)

在文章《线程间数据传递–多对多队列CXMulToMulQueue》中给出了一种多对多队列CXMulToMulQueue的实现,所有入队和出队使用同一个锁,当数据传递频繁时多个线程访问队列必然会导致锁竞争。

完成端口函数PostQueuedCompletionStatus(HANDLE, DWORD, ULONG_PTR, LPOVERLAPPED)传递的后三个参数会被函数GetQueuedCompletionStatus(HANDLE, LPDWORD, PULONG_PTR, LPOVERLAPPED, DWORD)原封不动的接收到,完成端口不会对这三个参数做任何操作,其中特别指出LPOVERLAPPED可以不是指向OVERLAPPED结构的指针。利用这个特性,把需要传递的数据地址直接投递到完成端口,由完成端口内部做访问互斥处理,可以有效减少由于锁竞争导致的耗时。
阅读剩余部分 –

单一结构内存池

在写完成端口时Overlapped以及Socket需要重复回收再利用,设计了一种池的结构用于内存分配释放管理,后来遇到多线程间数据传递时,这种结构也适用。池结构使用map管理分配的内存,以内存地址为key,实际存放的值表示该内存是否被占用,使用vector存放回收空闲的内存,分配内存时若vector中有空闲则取出最后一个,从vector中取出最后一个效率比直接在map中查询第一个空闲的要高的多,在回收内存时需要定位到指定内存位置,使用map存储查询效率比直接遍历高。这里以之前文章中介绍到的可变缓冲区CXVarBuf为固定单一结构,给出内存分配释放管理池结构类。
阅读剩余部分 –

线程间数据传递–多对多队列CXMulToMulQueue

线程间数据传递有以下几种形式:

  • 一对一(入队出队严格有序);
  • 多对一(入队无序出队有序);
  • 一对多(入队有序出队无序);
  • 多对多(入队无序出队无序);

一对一适用于数据入队和出队被处理完成的顺序必须严格一致的情况,比如客户端Socket读线程读取数据解析包后交给主线程去处理,客户端逻辑处理对服务器下发包的顺序有严格依赖性,这里就必须使用这种一对一形式。

多对一这种形式典型的用于网关服务器把来自客户端数据转发给逻辑服务器,网关服务器会有多个工作线程用于并发接收来自客户端的数据,转交给与逻辑服务器建立连接的Socket写线程。

一对多这种形式多用于任务频率不会太高,任务相互对立且处理比较慢,需要开多个线程并发处理。

多对多这种形式用于任务相互对立,允许多个线程发起任务,同时会开启多个线程执行任务。

线程间数据传递通常传递的并不是数据本身而是数据存放的地址,传递地址相对于传递数据本身减少了数据拷贝过程,这里一定要保证传递的地址在数据被处理完之前不能够被销毁。比较容易想到的一种方式是发送数据时,在堆上申请一块内存并把数据拷贝到这块内存上,把地址发送出去,接收方处理完成后释放这块内存,如果数据传递频率很少使用这种方式没有问题,如果频率很高就会有很大问题,每次不断的申请和释放内存会浪费很多CPU资源,这种情况下需要采用内存池机制进行内存的申请和释放,内存池机制会在其他文章中介绍。

下面给出一个简单的多对多队列类,可以指定用于处理数据的工作线程数量,投递数据接口多线程安全。这里用于传递数据的队列使用临界区进行互斥访问,当有多个工作线程时必然会产生锁竞争,工作线程会由于需要等待锁消耗很多时间,后面使用完成端口内部的队列替代自己写的队列,把互斥访问交给系统去做,可有效减少由于锁竞争导致的耗时。
阅读剩余部分 –

线程的创建_beginthreadex

  • 使用_beginthreadex创建线程替换CreateThread;
  • 线程指针类型参数不能传递指向栈内的地址;
  • 创建线程返回的句柄在不使用时需要调用CloseHandle关闭;
  • 尽量保证线程内操作的数据都是由线程参数传入而不直接使用全局变量;
  • 线程内操作数据必须要确定是否需要进行加锁互斥访问;
  • 尽量保证线程正常优雅的退出;
  • 线程退出时确定是否需要对传入的参数进行释放;

示例代码如下:
阅读剩余部分 –

分类目录

文章归档