❶ C语言可以实现 中断 和 多线程 这类功能吗
“晕,C语言不是灰常强大,无所不能吗?怎么有人说C语言不能实现 中断 和多线程??”这句话要分两部分来说,首先“晕,C语言不是灰常强大,无所不能吗?”。没有任何一种语言可以无所不能,原因很简单,任何的语言都脱离不了编译工具,而编译工具脱离不了编译环境。由于编译环境的不同,因此编译工具也有所不同,有得只针对JAVA,有得指针对C++,有得只针对C#。不管C语言多厉害,如果编译工具不支持,那也没有办法在这个编译工具上编译,以至于没有办法在那个编译工具的编译环境中运行。所以不能说无所不能。
“怎么有人说C语言不能实现 中断 和多线程啊”,这是一个概念性问题。纯粹的C语言只是一个工具,更多的是一种定义,一种格式,可以抽象成一种风格。就像定义一个整型变量i。为什么你不能用integer i定义,非得int i。例如函数的编写形式,命名规则等等。假如按照C语言的这些规则来编写程序,同时编译工具支持C语言,提供中断库,还有多线程库,那么C语言同样也可以实现中断和多线程。举个例子:例如你手头上只有一个TC编译工具,虽然他支持C语言,但是只能编译16位的DOS程序,碍于这个编译工具的局限性,所以你永远也写不出像Windows操作系统那种带窗口界面的Win32程序,也不能写一个针对.NET框架的网络服务程序。同样的,假如你要开发一个Windows软件,使用VC编译器,而这个编译工具本身带多线程库,同时支持Windows系统的很多调用,所以你完全可以以C语言的风格在这个编译器中调用各种Win32 SDK,开发一个多线程的Windows应用程序。假如你要使用中断,在Windows环境下可以使用微软提供的DDK(驱动开发包),他同样支持C语言,那么你就可以通过这个开发包调用很多中断。在linux环境下,不需要开发包就可以直接调用,因为Linux自带了很多系统调用都是开放的。头文件声明直接就在Linux文件系统的Sys目录下。所以说他仅仅是一种风格。依赖于编译环境的系统调用同样也依赖于编译环境提供的链接库。
❷ 编译器如何处理多线程程序
这是一个多线程例子,里面只有两个线程,是生产者/消费者模式,已编译通过,注释很详细,
如下:
/* 以生产者和消费者模型问题来阐述Linux线程的控制和通信你
生产者线程将生产的产品送入缓冲区,消费者线程则从中取出产品。
缓冲区有N个,是一个环形的缓冲池。
*/
#include <stdio.h>
#include <pthread.h>
#define BUFFER_SIZE 16
struct prodcons
{
int buffer[BUFFER_SIZE];/*实际存放数据的数组*/
pthread_mutex_t lock;/*互斥体lock,用于对缓冲区的互斥操作*/
int readpos,writepos; /*读写指针*/
pthread_cond_t notempty;/*缓冲区非空的条件变量*/
pthread_cond_t notfull;/*缓冲区未满 的条件变量*/
};
/*初始化缓冲区*/
void pthread_init( struct prodcons *p)
{
pthread_mutex_init(&p->lock,NULL);
pthread_cond_init(&p->notempty,NULL);
pthread_cond_init(&p->notfull,NULL);
p->readpos = 0;
p->writepos = 0;
}
/*将产品放入缓冲区,这里是存入一个整数*/
void put(struct prodcons *p,int data)
{
pthread_mutex_lock(&p->lock);
/*等待缓冲区未满*/
if((p->writepos +1)%BUFFER_SIZE ==p->readpos)
{
pthread_cond_wait(&p->notfull,&p->lock);
}
p->buffer[p->writepos] =data;
p->writepos++;
if(p->writepos >= BUFFER_SIZE)
p->writepos = 0;
pthread_cond_signal(&p->notempty);
pthread_mutex_unlock(&p->lock);
}
/*从缓冲区取出整数*/
int get(struct prodcons *p)
{
int data;
pthread_mutex_lock(&p->lock);
/*等待缓冲区非空*/
if(p->writepos == p->readpos)
{
pthread_cond_wait(&p->notempty ,&p->lock);//非空就设置条件变量notempty
}
/*读书据,移动读指针*/
data = p->buffer[p->readpos];
p->readpos++;
if(p->readpos == BUFFER_SIZE)
p->readpos = 0;
/*设置缓冲区未满的条件变量*/
pthread_cond_signal(&p->notfull);
pthread_mutex_unlock(&p->lock);
return data;
}
/*测试:生产站线程将1 到1000的整数送入缓冲区,消费者线程从缓冲区中获取整数,两者都打印信息*/
#define OVER (-1)
struct prodcons buffer;
void *procer(void *data)
{
int n;
for( n=0;n<1000;n++)
{
printf("%d ------>\n",n);
put(&buffer,n);
}
put(&buffer,OVER);
return NULL;
}
void *consumer(void *data)
{
int d;
while(1)
{
d = get(&buffer);
if(d == OVER)
break;
else
printf("----->%d\n",d);
}
return NULL;
}
int main()
{
pthread_t th_p,th_c;
void *retval;
pthread_init(&buffer);
pthread_create(&th_p,NULL,procer,0);
pthread_create(&th_c,NULL,consumer,0);
/*等待两个线程结束*/
pthread_join(th_p, &retval);
pthread_join(th_c,&retval);
return 0;
}
❸ c的多线程实现
像LINUX那种民间系统应该不会有CPU的优化指令,好多CPU都是针对WINDOWS优化的,只能说双核处理多线程比单核要快一倍而已。
❹ C语言编译器是否支持多线程
C语言编译器有很多,只要不是太旧的都支持多线程。C语言本身是没有多线程的概念的,都是操作系统提供支持,所以不同操作系统中的多线程实现起来可能完全不一样。
❺ 如何让makefile支持多线程
在Linux下编译个多线程命令为:
gcc -lpthread -o file file.c
在Linux下用交叉编译器编译个在uc下运行多线程makefile文件如下:
CFLAGS = -Wall -Os -D -D__linux__ -Dunix -D__uClinux__ -DEMBED
LDFLAGS =-Wl,-elf2flt
LOCAL_LIBS = /usr/local/arm-elf/lib/libpthread.a
CC = arm-elf-gcc
LD = arm-elf-gcc
TARGT = test
OBJ = $(TARGT).o
SRC = $(TARGT).c
all: $(TARGT)
%.o:%.c
$(CC) $(CFLAGS) -c $< -o $@
$(TARGT) :$(OBJ) $(LOCAL_LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LOCAL_LIBS) $(LDLIBS)
clean:
-rm -f $(EXEC) *.elf *.gdb *.o
❻ gcc编译线程程序,为什么要加-lpthread,头文件已经包含了<pthread.h>了啊
-lpthread是链接库,
<pthread.h>只有申明,实现部分都在库里面。
创建线程时一般是把函数的指针做参数,所以要加一个取地址符号。
ret=pthread_create(&id,NULL,(void *)&thread,NULL);
另外,建议要检查一下创建线程的返回值ret是否成功,防止影响后面的代码。
(6)编译器后端多线程扩展阅读:
每个语言编译器都是独立程序,此程序可处理输入的原始码,并输出组合语言码。全部的语言编译器都拥有共通的中介架构:一个前端解析符合此语言的原始码,并产生一抽象语法树,以及一翻译此语法树成为GCC的暂存器转换语言〈RTL〉的后端。
编译器最佳化与静态程序码解析技术(例如FORTIFY_SOURCE,一个试图发现缓冲区溢位〈buffer overflow〉的编译器)在此阶段应用于程序码上。最后,适用于此硬件架构的组合语言程序码以Jack Davidson与Chris Fraser发明的算法产出。
❼ 什么是编译器
编译器
编译器是一种特殊的程序,它可以把以特定编程语言写成的程序变为机器可以运行的机器码。我们把一个程序写好,这时我们利用的环境是文本编辑器。这时我程序把程序称为源程序。在此以后程序员可以运行相应的编译器,通过指定需要编译的文件的名称就可以把相应的源文件(通过一个复杂的过程)转化为机器码了。
[编辑]编译器工作方法
首先编译器进行语法分析,也就是要把那些字符串分离出来。然后进行语义分析,就是把各个由语法分析分析出的语法单元的意义搞清楚。最后生成的是目标文件,我们也称为obj文件。再经过链接器的链接就可以生成最后的可执行代码了。有些时候我们需要把多个文件产生的目标文件进行链接,产生最后的代码。我们把一过程称为交叉链接。
一个现代编译器的主要工作流程如下:
* 源程序(source code)→预处理器(preprocessor)→编译器(compiler)→汇编程序(assembler)→目标程序(object code)→连接器(链接器,Linker)→可执行程序(executables)
工作原理
编译是从源代码(通常为高级语言)到能直接被计算机或虚拟机执行的目标代码(通常为低级语言或机器言)。然而,也存在从低级语言到高级语言的编译器,这类编译器中用来从由高级语言生成的低级语言代码重新生成高级语言代码的又被叫做反编译器。也有从一种高级语言生成另一种高级语言的编译器,或者生成一种需要进一步处理的的中间代码的编译器(又叫级联)。
典型的编译器输出是由包含入口点的名字和地址以及外部调用(到不在这个目标文件中的函数调用)的机器代码所组成的目标文件。一组目标文件,不必是同一编译器产生,但使用的编译器必需采用同样的输出格式,可以链接在一起并生成可以由用户直接执行的可执行程序。
编译器种类
编译器可以生成用来在与编译器本身所在的计算机和操作系统(平台)相同的环境下运行的目标代码,这种编译器又叫做“本地”编译器。另外,编译器也可以生成用来在其它平台上运行的目标代码,这种编译器又叫做交叉编译器。交叉编译器在生成新的硬件平台时非常有用。“源码到源码编译器”是指用一种高级语言作为输入,输出也是高级语言的编译器。例如: 自动并行化编译器经常采用一种高级语言作为输入,转换其中的代码,并用并行代码注释对它进行注释(如OpenMP)或者用语言构造进行注释(如FORTRAN的DOALL指令)。
预处理器(preprocessor)
作用是通过代入预定义等程序段将源程序补充完整。
编译器前端(frontend)
前端主要负责解析(parse)输入的源程序,由词法分析器和语法分析器协同工作。词法分析器负责把源程序中的‘单词’(Token)找出来,语法分析器把这些分散的单词按预先定义好的语法组装成有意义的表达式,语句 ,函数等等。 例如“a = b + c;”前端词法分析器看到的是“a, =, b , +, c;”,语法分析器按定义的语法,先把他们组装成表达式“b + c”,再组装成“a = b + c”的语句。 前端还负责语义(semantic checking)的检查,例如检测参与运算的变量是否是同一类型的,简单的错误处理。最终的结果常常是一个抽象的语法树(abstract syntax tree,或 AST),这样后端可以在此基础上进一步优化,处理。
编译器后端(backend)
编译器后端主要负责分析,优化中间代码(Intermediate representation)以及生成机器代码(Code Generation)。
一般说来所有的编译器分析,优化,变型都可以分成两大类: 函数内(intraproceral)还是函数之间(interproceral)进行。很明显,函数间的分析,优化更准确,但需要更长的时间来完成。
编译器分析(compiler analysis)的对象是前端生成并传递过来的中间代码,现代的优化型编译器(optimizing compiler)常常用好几种层次的中间代码来表示程序,高层的中间代码(high level IR)接近输入的源程序的格式,与输入语言相关(language dependent),包含更多的全局性的信息,和源程序的结构;中层的中间代码(middle level IR)与输入语言无关,低层的中间代码(Low level IR)与机器语言类似。 不同的分析,优化发生在最适合的那一层中间代码上。
常见的编译分析有函数调用树(call tree),控制流程图(Control flow graph),以及在此基础上的变量定义-使用,使用-定义链(define-use/use-define or u-d/d-u chain),变量别名分析(alias analysis),指针分析(pointer analysis),数据依赖分析(data dependence analysis)等等。
上述的程序分析结果是编译器优化(compiler optimization)和程序变形(compiler transformation)的前提条件。常见的优化和变新有:函数内嵌(inlining),无用代码删除(Dead code elimination),标准化循环结构(loop normalization),循环体展开(loop unrolling),循环体合并,分裂(loop fusion,loop fission),数组填充(array padding),等等。优化和变形的目的是减少代码的长度,提高内存(memory),缓存(cache)的使用率,减少读写磁盘,访问网络数据的频率。更高级的优化甚至可以把序列化的代码(serial code)变成并行运算,多线程的代码(parallelized,multi-threaded code)。
机器代码的生成是优化变型后的中间代码转换成机器指令的过程。现代编译器主要采用生成汇编代码(assembly code)的策略,而不直接生成二进制的目标代码(binary object code)。即使在代码生成阶段,高级编译器仍然要做很多分析,优化,变形的工作。例如如何分配寄存器(register allocatioin),如何选择合适的机器指令(instruction selection),如何合并几句代码成一句等等。
❽ VC++6.0编译器中怎么设置编译选项为多线程
/MT
“Project Settings”
选择“C/C++”页面标签,然后在“Category”下拉式清单方块中选择“Code Generation”。在“Use Run-Time Library”下拉式清单方块中,可以看到用于“Release”设定的“Single-Threaded”和用于Debug设定的“Debug Single-Threaded”。将这些分别改为“Multithreaded”和“Debug Multithreaded”。
❾ linux下c、c++下多线程编译
C语言要求除main函数外 所有的函数必须先声明才能使用 你可以在函数定义的时候一起声明这个函数 但是在这个函数定义之前不能使用这个函数
下面用通俗点的语言讲: 你在main函数中调用了thread函数, 但是如果你把void *thread(void *vargp);删掉了, 那么编译器就找不到这个函数了(因为编译器是从前往后编译这个程序的) 因此编译器是通不过的
有两种方法, 一种就是像你之前写的 先声明这个函数 第二种是把void *thread(void *vargp){...}放到main函数的前面.
有些返回值和参数类型为int型的函数也可以不用声明, 编译器也能通过, 不过这是不建议的 也是不符合标准的
标准建议每个函数都应该给出它们的显式的声明
希望你懂了 嘿嘿
❿ C++多线程编程要用到哪些库如何编译这些库
千万别以为现在的C++没有原生的多线程库
OpenMP 是一个多线程库,不过他还需要编译器的支持,好在现在绝大多数都已经支持(这个可能是目前最流行的原生多线程库了)
C++的标准头process.h(太老的没有,2002年后的基本都有)中有操作进程和执行环境的函数,能实现简单的进程级或线程级并行操作。
使用起来非常非常方便。windows平台的C语言编译工具也都有这个头,unix平台上的unistd.h跟这个头很相似,函数名与用法也基本一样。
还有一些其他的第三方多线程库,你可以网上搜搜,但是注意是否跨平台等问题
如果你要使用操作系统相关的多线程API,那么也就没什么选择余地,windows上只能用windows的多线程API (参考MSDN) unix同理
OpenMP的优点是跨平台,功能丰富强大(例如提供了各种锁、信号等),代码改动也比较小,使用起来也非常方便快捷。缺点是没有像直接用系统API时透明感,毕竟使用系统API时,程序员完全控制了逻辑,非常直观,当然这也带来了错误风险和代码复杂度