请高手帮忙解释下这多线程的源代码,每句注释下 #include <stdio.h> #include <stdlib.h>
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请高手帮忙解释下这多线程的源代码,每句注释下 #include <stdio.h> #include <stdlib.h>相关的知识,希望对你有一定的参考价值。
#include <time.h>
#include "pthread.h"
#define BUFFER_SIZE 16
/* Circular buffer of integers. */
struct prodcons
int buffer[BUFFER_SIZE]; /* the actual data */
pthread_mutex_t lock; /* mutex ensuring exclusive access to buffer */
int readpos, writepos; /* positions for reading and writing */
pthread_cond_t notempty; /* signaled when buffer is not empty */
pthread_cond_t notfull; /* signaled when buffer is not full */
;
/*--------------------------------------------------------*/
/* Initialize a buffer */
void init(struct prodcons * b)
pthread_mutex_init(&b->lock, NULL);
pthread_cond_init(&b->notempty, NULL);
pthread_cond_init(&b->notfull, NULL);
b->readpos = 0;
b->writepos = 0;
/*--------------------------------------------------------*/
/* Store an integer in the buffer */
void put(struct prodcons * b, int data)
pthread_mutex_lock(&b->lock);
/* Wait until buffer is not full */
while ((b->writepos + 1) % BUFFER_SIZE == b->readpos)
printf("wait for not full\n");
pthread_cond_wait(&b->notfull, &b->lock);
/* Write the data and advance write pointer */
b->buffer[b->writepos] = data;
b->writepos++;
if (b->writepos >= BUFFER_SIZE) b->writepos = 0;
/* Signal that the buffer is now not empty */
pthread_cond_signal(&b->notempty);
pthread_mutex_unlock(&b->lock);
/*--------------------------------------------------------*/
/* Read and remove an integer from the buffer */
int get(struct prodcons * b)
int data;
pthread_mutex_lock(&b->lock);
/* Wait until buffer is not empty */
while (b->writepos == b->readpos)
printf("wait for not empty\n");
pthread_cond_wait(&b->notempty, &b->lock);
/* Read the data and advance read pointer */
data = b->buffer[b->readpos];
b->readpos++;
if (b->readpos >= BUFFER_SIZE) b->readpos = 0;
/* Signal that the buffer is now not full */
pthread_cond_signal(&b->notfull);
pthread_mutex_unlock(&b->lock);
return data;
#define OVER (-1)
struct prodcons buffer;
void * producer(void * data)
int n;
for (n = 0; n < 1000; n++) printf(" put-->%d\n", n);
put(&buffer, n);
put(&buffer, OVER);
printf("producer stopped!\n");
return NULL;
void * consumer(void * data)
int d;
while (1)
d = get(&buffer);
if (d == OVER ) break;
printf(" %d-->get\n", d);
printf("consumer stopped!\n");
return NULL;
int main(void)
pthread_t th_a, th_b;
void * retval;
init(&buffer);
pthread_create(&th_a, NULL, producer, 0);
pthread_create(&th_b, NULL, consumer, 0);
/* Wait until producer and consumer finish. */
pthread_join(th_a, &retval);
pthread_join(th_b, &retval);
return 0;
首先这是一个生产者和消费者问题。
生产者producer负责产生数据,然后通过put操作将数据放到缓冲区buf中。
消费者consumer负责显示数据,通过get操作从缓冲区buf中读取数据。
========》
先看主函数main(),
生产者和消费者分别用两个线程来实现。
主函数中的pthread_create()函数就是用来创建这两个线程的。
开始定义了两个变量th_a,th_b用来记录这两个线程的线程号。
线程的程序体分别是producer,consumer。
接下来的pthread_join用来等待两个线程结束。因为如果不等待,main函数的主线程会立即结束,而两个子线程还来不及完全执行。
=======》
下面来分别看producer,consumer这两个线程。
producer循环一百次,每次调用put往buffer中放数据,最后放一个OVER;
consumer循环用get从buffer中读到数据并打印,直到读取的数据位OVER数据时结束。
=======》
我们再分别来看put操作和get操作。
由于put和get都要访问buf,buf就是一个临界资源,为了解决这个临界资源,在使用buf之前,要对它加锁。
pthread_mutex_lock(b->lock)一个为信号量加锁的函数。每个信号量只能加锁一次(我说的可能不准确),如果执行该函数的时候,参数中的信号量已经被加锁,则该函数阻塞,直到信号量被解锁才继续执行。这样就能保证信号量所保护的临界资源能够被互斥的访问。
struct prodcons
int buffer[BUFFER_SIZE]; /* 这个就是循环缓冲区*/
pthread_mutex_t lock; /*这个是信号量,用来保证对缓冲区的互斥访问*/
int readpos, writepos; /* 这两个成员分别表示读位置和写位置*/
pthread_cond_t notempty; /* 这是表示缓冲区“非空”的条件信号量*/
pthread_cond_t notfull; /* 这是表示缓冲区“非满”的条件信号量*/
;
buf是一个循环的缓冲区,我们先来看缓冲区为空和满这两种状态时,读、写标记(readpos,writepos)的位置。
缓冲区为空时,readpos 和writepos指在同一位置;
换从去为满时,writepos位置的下一个位置就是readpos。
/* put负责把数据放到缓冲区*/
void put(struct prodcons * b, int data)
//首先对互斥信号量进行加锁
pthread_mutex_lock(&b->lock);
/* 这里就是判断缓冲区有没有满,用writepos+1与readpos比较,可以参考附图。
* 因为是循环缓冲区,所以要模BUFFER_SIZE 。
* 如果缓冲区满,将在while中等待,直到缓冲区非满,再继续执行。
*/
while ((b->writepos + 1) % BUFFER_SIZE == b->readpos)
printf("wait for not full\\n");
//如果已经满了,则等待消费者读取了数据后发出“非满”信号。
pthread_cond_wait(&b->notfull, &b->lock);
/* 当缓冲区非满时,将数据写入缓冲区中writepos对应的位置*/
b->buffer[b->writepos] = data;
//更新writepos到下一个位置
b->writepos++;
//循环利用缓冲区空间,如果超过了最大值,则从头开始。
if (b->writepos >= BUFFER_SIZE) b->writepos = 0;
/* 向消费者发送信号,告诉消费者缓冲取非空 */
pthread_cond_signal(&b->notempty);
//对互斥信号进行解锁。
pthread_mutex_unlock(&b->lock);
/*--------------------------------------------------------*/
/* get负责从缓冲区中读取数据 */
int get(struct prodcons * b)
int data;
//对互斥信号量进行加锁
pthread_mutex_lock(&b->lock);
/* 判断缓冲区是否为空,为空则等待*/
while (b->writepos == b->readpos)
printf("wait for not empty\\n");
pthread_cond_wait(&b->notempty, &b->lock);
/* 读取readpos位置的数据 */
data = b->buffer[b->readpos];
//更新readpos到下一个位置。
b->readpos++;
//循环利用缓冲区,回拨指针
if (b->readpos >= BUFFER_SIZE) b->readpos = 0;
/* 发信号给生产者,缓冲区非满,可以放数据了*/
pthread_cond_signal(&b->notfull);
//对互斥信号量进行解锁
pthread_mutex_unlock(&b->lock);
return data;
参考技术A 1111111111111111追问老兄,你这回答有点混吧?
求代码注释:计算机图形学的OpenGL画四面体。高手来吧。争取每句都注释下。谢谢
#include <gl/glut.h>
#define WIDTH 400
#define HEIGHT 400
#include <math.h>
#define ColoredVertex(c, v) do glColor3fv(c); glVertex3fv(v); while(0)
GLfloat angle = 0.0f;
void myDisplay(void)
static int list = 0;
if( list == 0 )
// 如果显示列表不存在,则创建
GLfloat
PointA[] = -0.5, -5*sqrt(5)/48, sqrt(3)/6,
PointB[] = 0.5, -5*sqrt(5)/48, sqrt(3)/6,
PointC[] = 0, -5*sqrt(5)/48, -sqrt(3)/3,
PointD[] = 0, 11*sqrt(6)/48, 0;
/*GLfloat
PointA[] = 0.5f, -sqrt(6.0f)/12, -sqrt(3.0f)/6,
PointB[] = -0.5f, -sqrt(6.0f)/12, -sqrt(3.0f)/6,
PointC[] = 0.0f, -sqrt(6.0f)/12, sqrt(3.0f)/3,
PointD[] = 0.0f, sqrt(6.0f)/4, 0;
*/
GLfloat
ColorR[] = 1, 0, 0,
ColorG[] = 0, 1, 0,
ColorB[] = 0, 0, 1,
ColorY[] = 1, 1, 0;
list = glGenLists(1);
glNewList(list, GL_COMPILE);
glBegin(GL_TRIANGLES);
// 平面ABC
ColoredVertex(ColorR, PointA);
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorB, PointC);
// 平面ACD
ColoredVertex(ColorR, PointA);
ColoredVertex(ColorB, PointC);
ColoredVertex(ColorY, PointD);
// 平面CBD
ColoredVertex(ColorB, PointC);
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorY, PointD);
// 平面BAD
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorR, PointA);
ColoredVertex(ColorY, PointD);
glEnd();
glEndList();
glEnable(GL_DEPTH_TEST);
// 已经创建了显示列表,在每次绘制正四面体时将调用它
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(angle, 1, 0.5, 0);
glCallList(list);
glPopMatrix();
glutSwapBuffers();
void myIdle(void)
++angle;
if( angle >= 360.0f )
angle = 0.0f;
myDisplay();
int main(int argc, char* argv[]) glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowPosition(200, 200);
glutInitWindowSize(WIDTH, HEIGHT);
glutCreateWindow("OpenGL 窗口");
glutDisplayFunc(&myDisplay);
glutIdleFunc(&myIdle);
glutMainLoop();
return 0;
#define WIDTH 400
#define HEIGHT 400
#include <math.h>
#define ColoredVertex(c, v) do glColor3fv(c); glVertex3fv(v); while(0) //这段就不用解释了吧……
GLfloat angle = 0.0f; //设定转角
void myDisplay(void) //绘图函数
static int list = 0;
if( list == 0 )
// 如果显示列表不存在,则创建
GLfloat //GLfloat为OpenGL用到的数据类型,与C的float基本一致
PointA[] = -0.5, -5*sqrt(5)/48, sqrt(3)/6, //此处为4个顶点的坐标,因为时3D坐标系下的,所以每个坐标有3个分量,分别对应X,Y,Z轴。至于各轴方向定义……默认下屏幕水平为X,竖直为Y,里外为Z。
PointB[] = 0.5, -5*sqrt(5)/48, sqrt(3)/6,
PointC[] = 0, -5*sqrt(5)/48, -sqrt(3)/3,
PointD[] = 0, 11*sqrt(6)/48, 0;
/*GLfloat
PointA[] = 0.5f, -sqrt(6.0f)/12, -sqrt(3.0f)/6,
PointB[] = -0.5f, -sqrt(6.0f)/12, -sqrt(3.0f)/6,
PointC[] = 0.0f, -sqrt(6.0f)/12, sqrt(3.0f)/3,
PointD[] = 0.0f, sqrt(6.0f)/4, 0;
*/
GLfloat
ColorR[] = 1, 0, 0, //定义颜色数组,每个数组为一个颜色,也含有3个分量,对应红,绿,蓝,分量范围[0,1],每种颜色都可看做是这3个颜色混合得到。可一自己改变下其中的数值看看具体效果。
ColorG[] = 0, 1, 0,
ColorB[] = 0, 0, 1,
ColorY[] = 1, 1, 0;
list = glGenLists(1);
glNewList(list, GL_COMPILE); //创建一个顶点表,这个表里包含有绘图的顶点信息
glBegin(GL_TRIANGLES); //开始绘图,(GL_TRIANGLES)表示绘制三角形
// 平面ABC
ColoredVertex(ColorR, PointA); //以颜色R绘制点A,以下类推,ColoredVertex()函数在程序开头定义了。
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorB, PointC);
// 平面ACD
ColoredVertex(ColorR, PointA);
ColoredVertex(ColorB, PointC);
ColoredVertex(ColorY, PointD);
// 平面CBD
ColoredVertex(ColorB, PointC);
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorY, PointD);
// 平面BAD
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorR, PointA);
ColoredVertex(ColorY, PointD);
glEnd();
glEndList(); //结束绘图 结束绘图顶点表。
glEnable(GL_DEPTH_TEST); //打开深度测试。打开深度测试的作用是:如果在场景中有多个物体,而它们相对观察者的距离不同(简单理解为远近),那么这个时候,前面的物体则可以挡住后面的物体(没错吧),使场景具有深度感。如果不打开深度测试,那么绘图会按绘制的顺序,后绘制的物体覆盖住现绘制的物体。这里要注意的是,深度仅影响物体重合时谁显示谁不显示,并不影响其3D效果,远处的物体仍然会变“小”,物体在空间中的位置仍为三维的。
// 已经创建了显示列表,在每次绘制正四面体时将调用它
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除颜色缓存和深度缓存
glPushMatrix(); //绘图坐标系入栈,可以简单理解为存下了这次画图时画笔的起始位置
glRotatef(angle, 1, 0.5, 0); //绘图坐标系绕(1,0.5,0)轴旋转angle角,可理解为模型绕该轴旋转angle角。
glCallList(list); //调用顶点表,绘制四面体模型
glPopMatrix(); //绘图坐标系出栈,则回到了刚才的绘图起始位置
glutSwapBuffers(); //使用双缓存(第一个在前面显示模型,另一个在后面绘制新的模型,当新模型绘制完毕后送给第一个缓存显示。这样不会出现模型上一些点已经绘制完了,而另一些点还在绘制的情况。)
void myIdle(void)
++angle;
if( angle >= 360.0f )
angle = 0.0f; //转角超过360度,将其置零。
myDisplay(); //绘制模型
int main(int argc, char* argv[]) glutInit(&argc, argv); //创建绘图窗口
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); //设置绘图模式
glutInitWindowPosition(200, 200); //设置窗口位置
glutInitWindowSize(WIDTH, HEIGHT); //设置窗口大小
glutCreateWindow("OpenGL 窗口"); //设置窗口标题
glutDisplayFunc(&myDisplay); //重复调用函数
glutIdleFunc(&myIdle);//重复调用函数
glutMainLoop(); //该循环用来对上述两个重复调用函数不断调用
return 0;
回答完毕。 参考技术A 很专业的,有专门论坛吧,用于#3D的一种方法。可是我们不采用,也不相信是有效的。换一个吧。
图杭GIs软件真3D软件。 参考技术B 我也不是很懂,你验收一下(有两个参考资料)
CS 535
WEILER-ATHERTON
PROBLEM
Implement Weiler-Atherton. You should draw each polygon in a different color and fill the clip areas generated with a third color.
NOTES:
The Weiler-Atherton algorithm is the most general of the clipping algorithms. We have two 2D polygons (may be convex or concave and they both may have holes). The polygon to be clipped is called the SUBJECT polygon and the polygon defining the clipping area is called the CLIP polygon. To make the algorithm work easier (in the data structures, etc.) we usually assume that the exterior vertices are given clockwise and the hole vertices are given counterclockwise. In clipping we usually want to find the parts of the subject polygon that are inside the clip polygon. However, this algorithm can be used in modeling to find the "union", "intersection", and "difference" of the polygons.
The data structures are several circular linked lists of vertices which are also linked together and the clipping is done by traversing these. The lists could be doubly linked. This enables the traversal in either direction at any node in the list. Starting at a particular node and traversing in one direction will produce the interior polygon(s) while starting at a different node and traversing can produce the outside. Note that producing the exterior does need the doubly linking and care must be taken in performing the traversal.
STEP 1:
The first phase of the building of the data structures occurs when we input the edges and put them in two linked lists - the SUBJ list and the CLIP list. The vertices are place in order from input (thus clockwise). There are separate lists for the exterior and for each hole. Thus, the initial build is a standard queue insert (input a vertex - insert it at end of list). Note that this creates a list in which a standard list traversal is equivalent to "walking around" the polygon edge visiting the vertices in order.
STEP 2:
The second phase of the list building is computing and inserting the INTERSECTION points. If we have a SUBJECT polygon edge (SVi to SVi+1) that intersects a CLIP polygon edge (CVj to CVj+1) at a point INTER. Note that the edges form straight lines that may intersect, we are assuming that the line segments SVi to SVi+1 intersects the line segment CVj to CVj+1. The intersection point INTER is then inserted on BOTH of the linked lists - SUBJ and CLIP. It is inserted BETWEEN SVi and SVi+1 on the SUBJ list and CVj and CVj+1 on the CLIP list. The idea is still that traversing the list using a standard list traversal we would encounter the points in their geometric order. Note that there may be several intersection points between any given pair of vertices and they must be inserted in the correct order in the lists. This is done by using the t and u values computed in the vector line intersection subprogram. Each intersection point thus has TWO nodes - one on each list (SUBJ and CLIP). We link these two entries together which provides a way of getting from one list to the other.
STEP 2.5:
Any straight line divides the plane into two half-planes. Thus each polygon edge (extended to a line) will divide the plane into two half-planes. Because we listed the vertices clockwise, we consider the half-plane to the right as containing the interior of the polygon. Thus the right half-plane is called the interior half-plane. If we consider ourselves as "walking along" a polygon edge, then we can categorize each of the INTERSECTION points as "entering" or "exiting". This is usually done from the SUBJ polygon's point of view. Thus, as we walk along the SUBJ polygon edge SVi to SVi+1 and we encounter intersection point INTER, we can ask the question - am I "entering" the CLIP polygon or am I "exiting" the CLIP polygon? The second part of computing the intersection point is to classify them as "entering" or "exiting". We create one or two lists - one for entering intersections and one for exiting intersections.
STEP3:
Once the lists are built the basic idea to do the clipping is as follows
Pick an entry from the ENTERING list - it will be an intersection point (and delete it)
Locate that point on the SUBJ list
Traverse the current (SUBJ) list until you find the next intersection point - it should be an exiting or entering point. Output each vertex encountered to some data structure, say POLY
Follow the link from the current (SUBJ) list to the other (CLIP) list and
Continue the traversal until you find the next intersection (Note: delete each entering intersection from the ENTERING list - not the linked lists. By deleting it we will get the distinct intersecting polygons and not duplicate a polygon multiple times).
Terminate the traversal when you get to an intersection that is the SAME as the initial one that you removed from the ENTERING list. At this point POLY will have one of the clip regions and can be output.
REPEAT the construction and output of POLY until the ENTERING list is empty.
Remark: For the exterior, try starting with an EXITING point. Start the traversal on the SUBJ list (same direction as the Interior). At what point do you need to use the double link and to traverse in the opposite direction? (Hint: look at the CLIP polygon list).
IMPLEMENTATION:
In the below data structures we place all of the vertices and intersection points in a 1D array and use the subscript instead of the actual coordinates.
const int MAXVERT = 500;
const int MAXPOLYV = 50;
const int MAXH = 10;
struct Point2D
float x,y;
;
typedef Point2D Vertices[MAXVERT];
enum VerType = ;
typedef struct ClipListRec * ClipPtr;
struct ClipListRec
int Vindex;
ClipPtr next;
VerType Kind;
float t;
ClipPtr otherList;
struct Polygon
int nVertex;
int vert[MAXPOLYV];
ClipPtr list;
struct GenPolygon
Polygon exterior;
int numHoles;
Polygon Holes[MAXH];
GenPolygon Sub,Clip;
int entering[MAXVERT],exiting[MAXVERT];
Vertices V;
int numVertex = 0; // size of the array of verticies
int clipPoly[MAXVERT]; // a clip polygon
int readPoint();
cin >> inX; cin >> inY;
if (numVertex < MAXVERT)
V[numVertex].x = inX;
V[numVertex].y = inY;
idNo = numVertex;
numVertex++;
else
idNo = -1;
return idNo;
void readPolygon (GenPolygon p)
cin >> p.exterior.nVertex;
for (i = 0; i < p.exterior.nVertex; i++)
newId = readPoint();
if (newId < 0)
error
else
insertAtRear (p.exterior.list,newId);
p.exterior.vert[i] = newId;
// now do the holes basically the same way
. . .
// the "main" program loop would then be (pseudocode)
while (!EMPTY(entering))
nextInter = delete (entering);
SEARCH (SubjectPolygon,nextInter,ptr1);
AddToOutputList (ptr1->. . .)
StartPoint = ptr1->. . .
ptr1 = prt1->next;
while (ptr1->. . . != StartPoint)
AddToOutputList (ptr1->. . .);
if (ptr1-> . . == INTERSECTION)
ptr1 = prt1->otherList->next;
else
ptr1 = ptr1->next;
FixListForOutput();
DrawPolygon();
EmptyOutputList();
参考资料:
以上是关于请高手帮忙解释下这多线程的源代码,每句注释下 #include <stdio.h> #include <stdlib.h>的主要内容,如果未能解决你的问题,请参考以下文章
求代码注释:计算机图形学的OpenGL画四面体。高手来吧。争取每句都注释下。谢谢
求解!!Qt,c++高手们快快显身手。。。 帮忙解释一下下面的程序,注释下每行吧,小弟是初学者,拜托!!
请帮忙解释下Dispatcher.BeginInoke((Action)(()=>....;...;...;),null);啥意思?