目录
public static void Sleep( int millisecondsTimeout )
public static void ResetAbort()
了解线程之前首先了解下什么是进程
进程:
狭义定义:进程是正在运行的程序的实例。
广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
进程的概念主要有两点:
第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。
第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。
线程:
是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
线程主要是由cpu寄存器 调用栈 线程本地存储器(TLS) 组成
cpu寄存器:主要记录当前执行线程的状态
调用栈:主要用来维护线程所调用的内存和数据
TLS:用来存放线程的状态信息
在单核处理器的电脑中
多线程的实现是通过cup在完成一个时间切片之后在活动的线程间进行切换执行来完成的,由于cup运行速度快,所以看上去是同一时刻执行了多个操作,实际同一时刻只有一个线程在处理。
在多核的电脑中
多线程被实现成混合时间片和真实的并发——不同的线程在不同的CPU上运行。由于操作系统的需要服务自己的线程,以及一些其他的应用程序。这几乎可以肯定仍然会出现一些时间切片。
System.Threading
Thread(ParameterizedThreadStart)
初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托。要执行的方法是有参的。
实例:
static void Main(string[] args) {
object obj = "xxx";
//第一种写法
Thread thread = new Thread(LudwigThread);
thread.Start(obj);
//第二种写法 delegate
Thread thread1 = new Thread(new ParameterizedThreadStart(LudwigThread));
thread1.Start(obj);
//第三种写法 lambda
Thread thread2 = new Thread((arg) => { LudwigThread(arg); });
thread2.Start(obj);
Console.WriteLine("mainThread");
Console.Read();
}
static void LudwigThread(object obj) {
Console.WriteLine("LudwigThread" + obj);
}
注:可传参的写法 注意参数类型必须为object.
打印:

Thread(ParameterizedThreadStart, Int32)
初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托,并指定线程的最大堆栈大小
实例:
static void Main(string[] args) {
object obj = "xxx";
//第一种写法
Thread thread = new Thread(LudwigThread, 1024);
thread.Start(obj);
//第二种写法 delegate
Thread thread1 = new Thread(new ParameterizedThreadStart(LudwigThread), 1024);
thread1.Start(obj);
//第三种写法 lambda
Thread thread2 = new Thread((arg) => { LudwigThread(arg); }, 1024);
thread2.Start(obj);
Console.WriteLine("mainThread");
Console.Read();
}
static void LudwigThread(object obj) {
Console.WriteLine("LudwigThread" + obj);
}
注: 根据.net api的解释 ,尽量不要使用这个重载
.Net API 地址:Thread 构造函数 (System.Threading) | Microsoft Learn
Thread(ThreadStart)
初始化 Thread 类的新实例。要执行的方法是无参的。
实例:
static void Main(string[] args) {
//第一种写法
Thread thread = new Thread(LudwigThread);
thread.Start();
//第二种写法 delegate
Thread thread1 = new Thread(new ThreadStart(LudwigThread));
thread1.Start();
//第三种写法 lambda
Thread thread2 = new Thread(() => { LudwigThread(); });
thread2.Start();
Console.WriteLine("mainThread");
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread");
}
打印:

Thread(ThreadStart, Int32)
初始化 Thread 类的新实例,指定线程的最大堆栈大小。
实例:
static void Main(string[] args) {
//第一种写法
Thread thread = new Thread(LudwigThread, 1024);
thread.Start();
//第二种写法 delegate
Thread thread1 = new Thread(new ThreadStart(LudwigThread), 1024);
thread1.Start();
//第三种写法 lambda
Thread thread2 = new Thread(() => { LudwigThread(); }, 1024);
thread2.Start();
Console.WriteLine("mainThread");
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread");
}
注: 根据.net api的解释 ,尽量不要使用这个重载
.Net API 地址:Thread 构造函数 (System.Threading) | Microsoft Learn
获取或设置线程的名称。
代码:
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
Console.WriteLine(thread.Name);
Console.Read();
}
static void LudwigThread() {
}
打印:

获取或设置一个值,该值指示线程的调度优先级。
代码:
static void Main(string[] args) {
Thread thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Priority = ThreadPriority.Highest;
thread.Start();
Thread thread1 = new Thread(KobThread);
thread1.Name = "KobThread";
thread1.Priority = ThreadPriority.Lowest;
thread1.Start();
for(int i = 0; i < 1000; i++) {
Console.Write("Y");
}
Console.Read();
}
static void LudwigThread() {
for(int i = 0; i < 1000; i++) {
Console.Write("X");
}
}
static void KobThread() {
for(int i = 0; i < 1000; i++) {
Console.Write("Z");
}
}
打印:
有打印可以看出所谓优先级并不是说优先级高的线程执行结束之后才执行优先级低的
获取一个值,该值指示当前线程的执行状态。
代码:
static void Main(string[] args) {
Thread thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
Console.WriteLine("mainThread: " + thread.IsAlive);
thread.Suspend();
Console.WriteLine("mainThread: " + thread.IsAlive);
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread: " + Thread.CurrentThread.Name);
}
打印:

获取或设置一个值,该值指示某个线程是否为后台线程。
注:须在线程start之前设置
代码:
1.不设置
static void Main(string[] args) {
Thread thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
thread.Suspend();
Console.WriteLine("mainThread: " + thread.IsAlive);
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread: " + Thread.CurrentThread.Name);
}
打印:

不设置IsBackground 后台线程 我们发现主线程结束后程序无法结束 会等待我们开的线程结束后整个程序才能结束
2.设置
static void Main(string[] args) {
Thread thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.IsBackground = true;
thread.Start();
thread.Suspend();
Console.WriteLine("mainThread: " + thread.IsAlive);
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread: " + Thread.CurrentThread.Name);
}
打印:

一旦主线程结束后整个程序结束 不管后台线程是否完成
获取一个值,该值包含当前线程的状态。
static void Main(string[] args) {
Thread thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Priority = ThreadPriority.Highest;
thread.Start();
Thread thread1 = new Thread(KobThread);
thread1.Name = "KobThread";
thread1.Priority = ThreadPriority.Lowest;
thread1.Start();
Console.WriteLine("---------" + thread.ThreadState);
Console.WriteLine("=========" + thread1.ThreadState);
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread");
}
static void KobThread() {
Console.WriteLine("KobThread");
}
打印:

CurrentContext:
获取线程正在其中执行的当前上下文。
上下文这篇博客有介绍 有兴趣可以看一下
C#综合揭秘——细说进程、应用程序域与上下文之间的关系 - 风尘浪子 - 博客园
CurrentCulture:
获取或设置当前线程的区域性。
代码:
static void Main(string[] args) {
Thread thread = new Thread(LudwigThread);
thread.Start();
Console.WriteLine("mainThread: " + thread.CurrentCulture);
Console.Read();
}
static void LudwigThread() {
}
打印:

CurrentPrincipal:
获取或设置线程的当前负责人(对基于角色的安全性而言)。
解释:
CurrentPrincipal 是.NET应用程序表示运行该进程的用户或服务帐户的标识的方式.
它可以包含一个或多个标识,并允许应用程序通过该IsInRole方法检查主体是否在角色中.
.NET中的大多数身份验证库都将验证用户的凭据,并将Thread类上的此静态属性设置为新的主体对象.
不同的线程可以有不同的主体,因为它们可能正在处理来自不同用户的请求(在ASP.NET Web应用程序HttpContext.User中
Thread.CurrentPrincipal为每个新请求复制)
拓展:
- 主题 -在安全上下文中, 主题 是请求访问 对象的 任何实体。这些是通用术语,用于表示请求访问的事物和针对其进行请求的事物。当您登录到应用程序时,您就是主题,而应用程序就是对象。当有人敲门时,访客是请求访问的对象,而您的家是请求访问的对象。
- 主体 - 由帐户,角色或其他唯一标识符表示的 主题 子集。当我们达到实现细节的级别时,主体是我们在访问控制列表中使用的唯一键。它们可能代表人类用户,自动化,应用程序,连接等。
- 用户 - 主体的 一个子集,通常是指操作员。区别随着时间的流逝而变得模糊,因为单词“用户”或“用户ID”通常与“帐户”互换。但是,当您需要区分 主体 的大类事物和交互性运营商的子集(以不确定性方式驱动交易)时,“用户”是正确的词。
代码:
static void Main(string[] args) {
Thread thread = new Thread(LudwigThread);
thread.Start();
Console.WriteLine("mainThread: " + Thread.CurrentPrincipal);
Console.Read();
}
static void LudwigThread() {
}
打印:

CurrentThread:
获取当前正在运行的线程。
代码:
static void Main(string[] args) {
Thread thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
Console.WriteLine("mainThread: " + Thread.CurrentThread.Name);
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread: " + Thread.CurrentThread.Name);
}
打印:

CurrentUICulture:
获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源。
代码:
static void Main(string[] args) {
Thread thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
Console.WriteLine("mainThread: " + thread.CurrentUICulture);
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread: " + Thread.CurrentThread.Name);
}
打印:

ExecutionContext:
获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。
IsThreadPoolThread:
获取一个值,该值指示线程是否属于托管线程池。
ManagedThreadId:
获取当前托管线程的唯一标识符。
代码:
static void Main(string[] args) {
Thread thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
Console.WriteLine("mainThread: " + thread.ManagedThreadId);
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread: " + Thread.CurrentThread.Name);
}
打印:

开始一个线程。
代码:
static void Main(string[] args) {
Thread thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Priority = ThreadPriority.Highest;
thread.Start();
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread");
}
Thread初始化之后 调用Start表示开始执行线程
让线程暂停一段时间。
static void Main(string[] args) {
Thread thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Priority = ThreadPriority.Highest;
thread.Start();
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread");
Thread.Sleep(10000);
Console.WriteLine("LudwigThread Wait");
}
打印:

10s之后

在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。调用此方法通常会终止线程。
1.在Start后调用
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Priority = ThreadPriority.Highest;
thread.Start();
thread.Abort();
Console.WriteLine("main");
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread");
Thread.Sleep(10000);
Console.WriteLine("LudwigThread Wait");
}
打印:

可以看到LudwigThread没有执行直接被中止
2.在线程WaitSleepJoin时调用
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Priority = ThreadPriority.Highest;
thread.Start();
Console.WriteLine("main");
Console.Read();
while(thread.ThreadState == ThreadState.WaitSleepJoin) {
thread.Abort();
}
}
static void LudwigThread() {
Console.WriteLine("LudwigThread");
Thread.Sleep(10000);
Console.WriteLine("LudwigThread Wait");
}
Abort调用 LudwigThread 线程尚未走完被终止
3.在线程挂起时调用
(1).
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Priority = ThreadPriority.Highest;
thread.Start();
Thread.Sleep(10);
thread.Suspend();
thread.Abort();
Console.WriteLine("main");
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread");
while(true) {
Console.WriteLine("X");
}
}
结果:

(2).尝试捕获异常
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
Thread.Sleep(10);
thread.Suspend();
try {
thread.Abort();
} catch(Exception ex) {
//thread.Resume();
}
Console.WriteLine("main");
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread");
while(true) {
try {
Console.WriteLine("X");
} catch(Exception ex) {
Console.WriteLine(ex);
}
}
}
没有调用 Resume 线程被阻塞

(3).
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
Thread.Sleep(10);
thread.Suspend();
try {
thread.Abort();
} catch(Exception ex) {
thread.Resume();
}
Console.WriteLine("main");
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread");
while(true) {
try {
Console.WriteLine("X");
} catch(Exception ex) {
Console.WriteLine(ex);
}
}
}
直到调用 Resume 后,才在挂起的线程中引发 ThreadAbortException。

4.线程中捕获中止
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Priority = ThreadPriority.Highest;
thread.Start();
Thread.Sleep(10);
//thread.Suspend();
thread.Abort();
Console.WriteLine("main");
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("LudwigThread");
while(true) {
try {
Console.WriteLine("X");
} catch(Exception ex) {
Console.WriteLine(ex);
}
}
}
打印:

取消为当前线程请求的 Abort。
代码:
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
Thread.Sleep(10);
thread.Abort();
Console.WriteLine("main");
Console.Read();
}
static bool reset = true;
static void LudwigThread() {
Console.WriteLine("LudwigThread");
while(reset) {
try {
Console.WriteLine("X");
} catch(Exception ex) {
//Thread.ResetAbort();
reset = false;
}
}
Console.WriteLine("end");
}
打印:

我们发现end没有被打印出来
尝试调用ResetAbort()
代码:
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
Thread.Sleep(10);
thread.Abort();
Console.WriteLine("main");
Console.Read();
}
static bool reset = true;
static void LudwigThread() {
Console.WriteLine("LudwigThread");
while(reset) {
try {
Console.WriteLine("X");
} catch(Exception ex) {
Thread.ResetAbort();
reset = false;
}
}
Console.WriteLine("end");
}
打印 :

end 被执行了
在继续执行标准的 COM 和 SendMessage 消息泵处理期间,阻塞调用线程,直到某个线程终止为止。此方法有不同的重载形式。
首先我们看下没有join的代码
代码:
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
for(int i = 0; i < 1000; i++) {
Console.Write("Y");
}
Console.Read();
}
static bool reset = true;
static void LudwigThread() {
for(int i = 0; i < 1000; i++) {
Console.Write("X");
}
}
打印:

XY无序打印
调用Join
代码:
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
thread.Join();
for(int i = 0; i < 1000; i++) {
Console.Write("Y");
}
Console.Read();
}
static bool reset = true;
static void LudwigThread() {
for(int i = 0; i < 1000; i++) {
Console.Write("X");
}
}
打印 :

Join阻塞了其他线程,只有当前线程结束之后才允许调用其他线程
中断处于 WaitSleepJoin 线程状态的线程。
首先还是先看不使用时的代码
代码:
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
Thread.Sleep(100);
//thread.Interrupt();
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("Start");
try {
Thread.Sleep(10000);
} catch(Exception ex) {
Console.WriteLine(ex);
}
Console.WriteLine("End");
}
打印 :

先打印Start 10s之后打印End
然后我们使用Interrupt()
代码:
static Thread thread;
static void Main(string[] args) {
thread = new Thread(LudwigThread);
thread.Name = "LudwigThread";
thread.Start();
Thread.Sleep(100);
thread.Interrupt();
Console.Read();
}
static void LudwigThread() {
Console.WriteLine("Start");
Thread.Sleep(10000);
Console.WriteLine("End");
}
打印:

抛出异常并且直接打印出了End
public static LocalDataStoreSlot AllocateDataSlot()
在所有的线程上分配未命名的数据槽。为了获得更好的性能,请改用以 ThreadStaticAttribute 属性标记的字段。
public static LocalDataStoreSlot AllocateNamedDataSlot( string name)
在所有线程上分配已命名的数据槽。为了获得更好的性能,请改用以 ThreadStaticAttribute 属性标记的字段。
public static void BeginCriticalRegion()
通知主机执行将要进入一个代码区域,在该代码区域内线程中止或未经处理的异常的影响可能会危害应用程序域中的其他任务。
public static void BeginThreadAffinity()
通知主机托管代码将要执行依赖于当前物理操作系统线程的标识的指令。
public static void EndCriticalRegion()
通知主机执行将要进入一个代码区域,在该代码区域内线程中止或未经处理的异常仅影响当前任务。
public static void EndThreadAffinity()
通知主机托管代码已执行完依赖于当前物理操作系统线程的标识的指令。
public static void FreeNamedDataSlot(string name)
为进程中的所有线程消除名称与槽之间的关联。为了获得更好的性能,请改用以 ThreadStaticAttribute 属性标记的字段。
public static Object GetData( LocalDataStoreSlot slot )
在当前线程的当前域中从当前线程上指定的槽中检索值。为了获得更好的性能,请改用以 ThreadStaticAttribute 属性标记的字段。
public static AppDomain GetDomain()
返回当前线程正在其中运行的当前域。
public static AppDomain GetDomainID()
返回唯一的应用程序域标识符。
public static LocalDataStoreSlot GetNamedDataSlot( string name )
查找已命名的数据槽。为了获得更好的性能,请改用以 ThreadStaticAttribute 属性标记的字段。
public static void MemoryBarrier()
按如下方式同步内存存取:执行当前线程的处理器在对指令重新排序时,不能采用先执行 MemoryBarrier 调用之后的内存存取,再执行 MemoryBarrier 调用之前的内存存取的方式。
public static void SetData( LocalDataStoreSlot slot, Object data )
在当前正在运行的线程上为此线程的当前域在指定槽中设置数据。为了获得更好的性能,请改用以 ThreadStaticAttribute 属性标记的字段。
public static void SpinWait( int iterations )
导致线程等待由 iterations 参数定义的时间量。
public static byte VolatileRead( ref byte address )
public static double VolatileRead( ref double address )
public static int VolatileRead( ref int address )
public static Object VolatileRead( ref Object address )
读取字段值。无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。此方法有不同的重载形式。这里只给出了一些形式。
public static void VolatileWrite( ref byte address, byte value )
public static void VolatileWrite( ref double address, double value )
public static void VolatileWrite( ref int address, int value )
public static void VolatileWrite( ref Object address, Object value )
立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。此方法有不同的重载形式。这里只给出了一些形式。
public static bool Yield()
导致调用线程执行准备好在当前处理器上运行的另一个线程。由操作系统选择要执行的线程。
有些属性和方法没有添加代码和运行结果 有些引用了一些大佬的博客,想要完全理解Thread的同学一定要耐下性子仔细阅读,有些需要使用不求甚解的同学也要把几个主要的属性和方法看一遍,不管是怎样 一定是先理解了什么是线程 他的工作原理是什么,然后再学习其方法和属性,最后最后一定要自己写一遍几个常用的方法和属性,才能真的记得住。
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。
我的工作要求我为某些测试自动生成电子邮件。我一直在四处寻找,但未能找到可以快速实现的合理解决方案。它需要在outlook而不是其他邮件服务器中,因为我们有一些奇怪的身份验证规则,我们需要保存草稿而不是仅仅发送邮件的选项。显然win32ole可以做到这一点,但我找不到任何相当简单的例子。 最佳答案 假设存储了Outlook凭据并且您设置为自动登录到Outlook,WIN32OLE可以很好地完成此操作:require'win32ole'outlook=WIN32OLE.new('Outlook.Application')message=
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
//1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json
在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q