苹果guide学习笔记1<About Threaded Programming>

Multiple threads can improve an application’s perceived responsiveness.

多线程可以提升应用的感知的回应能力

Multiple threads can improve an application’s real-time performance on multicore systems.

多线程可以提升应用真正的性能在多核系统上

Threading Terminology

多线程的术语

thread线程

The term thread is used to refer to a separate path of execution for code

术语线程就是用于指代码的单独执行路径

process进程

The term process is used to refer to a running executable, which can encompass multiple threads

术语进程用于指运行的可执行文件,其可以包含多个线程

task任务

The term task is used to refer to the abstract concept of work that needs to be performed

术语任务用于指代需要执行的工作的抽象概念

Because threads in a single application share the same memory space, they have access to all of the same data structures. If two threads try to manipulate the same data structure at the same time, one thread might overwrite another’s changes in a way that corrupts the resulting data structure.

因为在一个应用里,线程是共享相同的存储空间。他们可以访问全部相同的数据结构。假如2个线程在同一时间试着去操作相同的数据结构,一个线程可能覆盖了另外一个的更改。破坏生成的数据结构。

Alternative technologies to threads

关于线程,可供选择的技术

Operation objects

how to use operation objects

you can seeConcurrency Programming Guide.

https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008091

Grand Central Dispatch

how to use GCD同上链接

Idle-time notifications

For tasks that are relatively short and very low priority, idle time notifications let you perform the task at a time when your application is not as busy

对于相对较短或者优先级很低的任务,当你的应用并不是繁忙的,那么空闲时间的通知让你去执行一次任务

Asynchronous functions

The system interfaces include many asynchronous functions that provide automatic concurrency for you. These APIs may use system daemons and processes or create custom threads to perform their task and return the results to you. (The actual implementation is irrelevant because it is separated from your code.) As you design your application, look for functions that offer asynchronous behavior and consider using them instead of using the equivalent synchronous function on a custom thread.

系统的接口包含了许多异步的,用来给你们提供自动并发的函数/方法。这些apis可能使用系统的守护进程或者程序或者创建定制的线程去执行任务,并且返回结果给你。(实际的实现是不想关的,因为它和你们的代码是分离的)。当你设计你的程序,查找提供异步特性的函数,那么考虑在定制的线程上使用相同的同步函数去代替直接使用异步特性的函数

Timers定时器

You can use timers on your application’s main thread to perform periodic tasks that are too trivial to require a thread, but which still require servicing at regular intervals. For information on timers, see Timer Sources.

你可以在应用的主线程里使用定时器执行需要一个线程而又麻烦的周期任务,任务在定期的间隔里,仍然会去服务。

Although the underlying implementation mechanism for threads is Mach threads, you rarely (if ever) work with threads at the Mach level. Instead, you usually use the more convenient POSIX API or one of its derivatives. The Mach implementation does provide the basic features of all threads, however, including the preemptive execution model and the ability to schedule threads so they are independent of each other.

虽然线程的底层实现机制是mach线程,很少在mach级别使用线程工作。代替你常常使用更有效的POSIX的API或者它的派生类的其中之一。Mach实现提供了线程所有的基础特性,包含优先执行模型,并且有能力去调度线程因此它们是相互独立的。

Cocoa threads使用nsthread和nsobject to spaw a thread

POSIX threads面向c接口

When you create a new thread, you must specify an entry-point function (or an entry-point method in the case of Cocoa threads) for that thread. This entry-point function constitutes the code you want to run on the thread. When the function returns, or when you terminate the thread explicitly, the thread stops permanently and is reclaimed by the system. Because threads are relatively expensive to create in terms of memory and time, it is therefore recommended that your entry point function do a significant amount of work or set up a run loop to allow for recurring work to be performed

当你创建了一个新的线程,你必须给线程指定它的入口函数,这个入口函数由你想要在线程上跑的代码组成。当你的函数返回,或者当你永久终止了线程,那么线程永久停止了。并且被系统回收了!因为线程在内存和时间方面相对昂贵。因此推荐你的入口函数执行大量的工作或者设置一个run loop用来允许执行重复的工作.

Run Loops

A run loop is a piece of infrastructure used to manage events arriving asynchronously on a thread. A run loop works by monitoring one or more event sources for the thread. As events arrive, the system wakes up the thread and dispatches the events to the run loop, which then dispatches them to the handlers you specify. If no events are present and ready to be handled, the run loop puts the thread to sleep.

run loop是一个基础设施用于管理在线程上异步到达的事件.一个run loop通过监控线程的一个或多个事件源来工作。当事件达到了,系统唤醒了线程,并且将事件分发到run loop。然后将它们分派到指定的处理程序。假如没有事件出现并准备好处理。run loop让线程休眠.

You are not required to use a run loop with any threads you create but doing so can provide a better experience for the user. Run loops make it possible to create long-lived threads that use a minimal amount of resources. Because a run loop puts its thread to sleep when there is nothing to do, it eliminates the need for polling, which wastes CPU cycles and prevents the processor itself from sleeping and saving power.

你不需要使用你创建的任何线程的run loop,但是这样做能给用户提供更好的体验。run loop使得创建使用最少的资源的生命周期较长的线程变得可能。因为一个run loop让它的线程休眠,它消除了轮询的需要,这浪费了cpu周期并且防止了处理器本身的睡眠和省电.

To configure a run loop, all you have to do is launch your thread, get a reference to the run loop object, install your event handlers, and tell the run loop to run. The infrastructure provided by OS X handles the configuration of the main thread’s run loop for you automatically. If you plan to create long-lived secondary threads, however, you must configure the run loop for those threads yourself.

要配置一个run loop,所有你需要做的是启动你的线程,获取到run loop对象的引用.安装你的事件处理者,并且告诉run loop可以运行了。os x提供的基础设施可以自动的处理主线程run loop的配置,假如你计划创建生命周期长的子线程,你必须自己给那些线程配置run loop,

Synchronization Tools

同步工具

One of the hazards of threaded programming is resource contention among multiple threads. If multiple threads try to use or modify the same resource at the same time, problems can occur. One way to alleviate the problem is to eliminate the shared resource altogether and make sure each thread has its own distinct set of resources on which to operate. When maintaining completely separate resources is not an option though, you may have to synchronize access to the resource using locks, conditions, atomic operations, and other techniques.

线程编程的危险之一是多个线程之间的资源竞争,假如多个线程试着同时使用或者修改资源,那么问题来了,缓解问题的一个方法是完全消除共享的资源,并且确保每个线程有自己独特的资源集合来操作。当维护完全独立的资源不是一个选择,你可能必须使用锁,条件锁,原子操作和其他技术来同步对资源的访问.

Locks provide a brute force form of protection for code that can be executed by only one thread at a time. The most common type of lock is mutual exclusion lock, also known as a mutex. When a thread tries to acquire a mutex that is currently held by another thread, it blocks until the lock is released by the other thread. Several system frameworks provide support for mutex locks, although they are all based on the same underlying technology. In addition, Cocoa provides several variants of the mutex lock to support different types of behavior, such as recursion. For more information about the available types of locks, see Locks.

锁为一次只能由一个线程执行的代码提供了强有力的保护形式,最常见的锁类型是互斥锁,当一个线程试着去获取当前由另一个线程持有的互斥锁,它会阻塞直到锁被另外一个线程释放了。几个系统框架提供了对互斥锁的支持.虽然它们全部都基于相同的基础技术,此外,cocoa提供了互斥锁的几种方式,以不同类型的行为,如递归。有关可用类型的锁的更多信息,请参阅locks

In addition to locks, the system provides support for conditions, which ensure the proper sequencing of tasks within your application. A condition acts as a gatekeeper, blocking a given thread until the condition it represents becomes true. When that happens, the condition releases the thread and allows it to continue. The POSIX layer and Foundation framework both provide direct support for conditions. (If you use operation objects, you can configure dependencies among your operation objects to sequence the execution of tasks, which is very similar to the behavior offered by conditions.)

除了锁,系统提供了对条件锁的支持,确保了你的应用程序内任务的顺序排列.条件锁作为一个守门员,阻塞一个给定的线程,直到它表示的条件为true,当发生了,条件锁释放线程,允许它继续。

posix层和基础框架都为条件锁提供直接支持。

Although locks and conditions are very common in concurrent design, atomic operations are another way to protect and synchronize access to data. Atomic operations offer a lightweight alternative to locks in situations where you can perform mathematical or logical operations on scalar data types. Atomic operations use special hardware instructions to ensure that modifications to a variable are completed before other threads have a chance to access it.

虽然锁和条件锁在并发设计中非常普遍,原子操作是保护和同步数据访问的另外一种方式。在可以对标量数据类型执行数据和逻辑的运算情况下,原子操作提供了轻量级的锁的方法。原子操作使用特殊的硬件指令来确保在其他线程有机会访问变量之前完成对变量的修改.

Inter-thread Communication

线程间通信

Although a good design minimizes the amount of required communication, at some point, communication between threads becomes necessary. (A thread’s job is to do work for your application, but if the results of that job are never used, what good is it?) Threads may need to process new job requests or report their progress to your application’s main thread. In these situations, you need a way to get information from one thread to another. Fortunately, the fact that threads share the same process space means you have lots of options for communication.

虽然良好的设计使得所需通信的数量最小化,但在某些时刻,线程之间的通信变得有必要。(线程的工作是为你的应用程序做工作,但是如果该工作的结果从未被使用,那么它有什么好处?)线程可能需要处理新的作业请求或将其进度报告给应用程序的主线程。在这些情况下,你需要一种从一个线程获取信息到另一个线程的方法。幸运的是,线程共享相同的进程空间意味着你有很多选项可以进行通信.

There are many ways to communicate between threads, each with its own advantages and disadvantages. Configuring Thread-Local Storage lists the most common communication mechanisms you can use in OS X. (With the exception of message queues and Cocoa distributed objects, these technologies are also available in iOS.) The techniques in this table are listed in order of increasing complexity.

线程之间有许多方式进行通信,每个线程有它自己的好处和坏处。配置线程本地存储列出了你可以在os x中使用的最常见的通信机制。(除了消息队列和cocoa分布式对象之外,这些技术也可以在ios中使用)

Direct messaging

直接通信

Cocoa applications support the ability to perform selectors directly on other threads. This capability means that one thread can essentially execute a method on any other thread. Because they are executed in the context of the target thread, messages sent this way are automatically serialized on that thread. For information about input sources,

cocoa应用程序支持直接在其他线程上执行方法的功能。该功能意味着一个线程可以在任何其他线程上基本上执行一个方法。因为它们是在目标线程的上下人中执行的。所以以这种方式发送的消息将在该线程上自动序列化。有关输入源的信息see detail

Global variables, shared memory, and objects

全局变量,共享内存和对象

Another simple way to communicate information between two threads is to use a global variable, shared object, or shared block of memory. Although shared variables are fast and simple, they are also more fragile than direct messaging. Shared variables must be carefully protected with locks or other synchronization mechanisms to ensure the correctness of your code. Failure to do so could lead to race conditions, corrupted data, or crashes.

另外一种简单的方式在两个线程间传递信息是使用全局变量,共享对象或共享内存块.虽然共享变量是快速和简单的,但是它们比起直接消息更脆弱。共享变量必须使用锁或者其他同步机制仔细保护,确保代码的正确性。否则可能导致竞争条件,数据损坏和崩溃.

Conditions

Conditions are a synchronization tool that you can use to control when a thread executes a particular portion of code. You can think of conditions as gate keepers, letting a thread run only when the stated condition is met. For information on how to use conditions

条件锁是一个同步的工具,你可以使用它来控制线程什么时候执行特定的代码部分。你可以将条件锁视为守门员,只有当满足规定的条件时才允许线程运行。see detail

Run loop sources源

A custom run loop source is one that you set up to receive application-specific messages on a thread. Because they are event driven, run loop sources put your thread to sleep automatically when there is nothing to do, which improves your thread’s efficiency. For information about run loops and run loop sources

自定义的run loop源是你设置为接收特定于应用程序的消息的源代码。因为它们是事件驱动的。run loop源可以让你的线程自动进入休眠状态,这样可以提高线程的效率。see detail

Ports and sockets

Port-based communication is a more elaborate way to communication between two threads, but it is also a very reliable technique. More importantly, ports and sockets can be used to communicate with external entities, such as other processes and services. For efficiency, ports are implemented using run loop sources, so your thread sleeps when there is no data waiting on the port. For information about run loops and about port-based input sources, see Run Loops.

基于端口的通信是一种更加精细的两个线程之间的通信方式,但是它也是一种非常可靠的技术.更重要的是,可以使用端口和套接字与外部实体进行通信,比如其他进程和服务。为了效率,端口是使用run loop源实现的,因此当端口上没有数据等待时,你的线程将休眠。see detail

Message queues消息队列

The legacy Multiprocessing Services defines a first-in, first-out (FIFO) queue abstraction for managing incoming and outgoing data. Although message queues are simple and convenient, they are not as efficient as some other communications techniques. For more information about how to use message queues, see Multiprocessing Services Programming Guide.

传统的多处理服务定义了用于管理传入和传出数据的先入先出(FIFO)队列的抽象。虽然消息队列简单方便,但并不像其他一些通信技术那样有效。see detail

Cocoa distributed objects

Distributed objects is a Cocoa technology that provides a high-level implementation of port-based communications. Although it is possible to use this technology for inter-thread communication, doing so is highly discouraged because of the amount of overhead it incurs. Distributed objects is much more suitable for communicating with other processes, where the overhead of going between processes is already high. For more information, see Distributed Objects Programming Topics

分布式对象是一种cocoa的技术,可提供基于端口的通信的高级实现。虽然可以使用这个技术进行跨线程通信,但是由于其引起的开销的数量,因此这样做非常不鼓励。分布式对象更适合于与其他进程通信,其中进程之间的开销已经很高了。see detail

Design Tips设计技巧

Avoid Creating Threads Explicitly避免显示创建线程

Writing thread-creation code manually is tedious and potentially error-prone and you should avoid it whenever possible. OS X and iOS provide implicit support for concurrency through other APIs. Rather than create a thread yourself, consider using asynchronous APIs, GCD, or operation objects to do the work. These technologies do the thread-related work behind the scenes for you and are guaranteed to do it correctly. In addition, technologies such as GCD and operation objects are designed to manage threads much more efficiently than your own code ever could by adjusting the number of active threads based on the current system load.

手动创建线程代码是乏味且可能出错,你应该尽可能避免。os x和ios通过其他api提供对并发的隐含支持,不是自己创建一个线程,而是考虑使用异步api,gcd或operation来完成工作。这些技术为你幕后线程相关工作,并保证正确执行.此外,gcd和operation等技术旨在通过根据当前系统负载调整活动线程的数量,从而比你自己的代码更有效的管理线程.see detail

Keep Your Threads Reasonably Busy

保持线程合理忙

If you decide to create and manage threads manually, remember that threads consume precious system resources. You should do your best to make sure that any tasks you assign to threads are reasonably long-lived and productive. At the same time, you should not be afraid to terminate threads that are spending most of their time idle. Threads use a nontrivial amount of memory, some of it wired, so releasing an idle thread not only helps reduce your application’s memory footprint, it also frees up more physical memory for other system processes to use

假如你决定手动创建和管理线程,记得线程会消耗宝贵的系统资源。你应该尽你最大努力确保你分配的线程相当的长寿命和高效。同时,你不应该害怕终止大部分时间闲置的线程。线程使用非常重要的内存,其中一些内存有线,因此释放空闲的线程不仅帮助减少你应用的内存占用,还可以释放更多的物理内存,以供其他系统进程使用.

Avoid Shared Data Structures

避免共享数据结构

The simplest and easiest way to avoid thread-related resource conflicts is to give each thread in your program its own copy of whatever data it needs. Parallel code works best when you minimize the communication and resource contention among your threads.

避免与线程相关的资源冲突的最简单办法是让程序中每一个线程都能够有它需要的任何数据的copy。当你最小化线程间的通信和资源争用时,并行代码的效果最佳.

Creating a multithreaded application is hard. Even if you are very careful and lock shared data structures at all the right junctures in your code, your code may still be semantically unsafe. For example, your code could run into problems if it expected shared data structures to be modified in a specific order. Changing your code to a transaction-based model to compensate could subsequently negate the performance advantage of having multiple threads. Eliminating the resource contention in the first place often results in a simpler design with excellent performance

创建多线程应用程序很困难,即使你在代码中的所有正确关键点非常小心并锁定共享数据结构,你的代码仍可能在语义上不安全。比如,如果希望以特定顺序去修改共享数据结构,你的代码可能会遇到问题。将代码更改为基于事务的模型进行补偿可能会导致多个线程的性能优势无效。首先消除资源争用通常可以使得简单的设计有更优的性能.

Threads and Your User Interface线程和你的用户界面

If your application has a graphical user interface, it is recommended that you receive user-related events and initiate interface updates from your application’s main thread. This approach helps avoid synchronization issues associated with handling user events and drawing window content. Some frameworks, such as Cocoa, generally require this behavior, but even for those that do not, keeping this behavior on the main thread has the advantage of simplifying the logic for managing your user interface

如果你的应用程序有图形用户界面,建议你从应用程序主线程接收与用户相关的事件并且启动界面更新。这种方法有助于避免与处理用户事件和绘制窗口内容相关的同步问题。一些框架,比如cocoa,通常需要这个行为,但是对于那些不行的框架,在主线程上保持这个行为具有简化管理用户界面的逻辑的优点。

There are a few notable exceptions where it is advantageous to perform graphical operations from other threads. For example, you can use secondary threads to create and process images and perform other image-related calculations. Using secondary threads for these operations can greatly increase performance. If you are not sure about a particular graphical operation though, plan on doing it from your main thread

有一些显着的例外,从其他线程执行图像操作是有利的。比如,你可以使用子线程来创建和处理图像并且执行其他与图像相关的计算。对这些操作使用子线程可以大大提高性能。假如你不确定某个特定的图形操作,则计划从主线程中去执行此操作.

Be Aware of Thread Behaviors at Quit Time

A process runs until all non-detached threads have exited. By default, only the application’s main thread is created as non-detached, but you can create other threads that way as well. When the user quits an application, it is usually considered appropriate behavior to terminate all detached threads immediately, because the work done by detached threads is considered optional. If your application is using background threads to save data to disk or do other critical work, however, you may want to create those threads as non-detached to prevent the loss of data when the application exits.

一个进程运行,直到所有的非分离线程退出。默认情况下,只有应用程序的主线程被创建为非分离。但是你可以创建其他的线程。当用户退出应用程序,通常认为立即终止全部分离的线程是适当的行为,因为分离线程完成的工作被认为是可选的。如果你的应用程序正在使用后台线程将数据保存到磁盘或者执行其他关键工作,则可能需要将这个线程创建为非分离,以防止程序退出时丢失数据.

Creating threads as non-detached (also known as joinable) requires extra work on your part. Because most high-level thread technologies do not create joinable threads by default, you may have to use the POSIX API to create your thread. In addition, you must add code to your application’s main thread to join with the non-detached threads when they do finally exit. For information on creating joinable threads

将线程创建为非分离需要额外的工作。因为大多数高级的线程技术默认不会给你创建可连接线程。所以你可能必须使用POSIX API创建线程。此外你必须在你的应用程序主线程添加代码,以便在最终退出时与非分离线程结合。see detail

If you are writing a Cocoa application, you can also use the applicationShouldTerminate: delegate method to delay the termination of the application until a later time or cancel it altogether. When delaying termination, your application would need to wait until any critical threads have finished their tasks and then invoke the replyToApplicationShouldTerminate: method

如果你正在编写cocoa应用程序,你也可以使用applicationShouldTerminate方法去延迟应用程序的终止,直到稍后再次完全取消。当延迟终止,你的应用程序将需要等到任何关键线程完成任务,然后调用replyToApplicationShouldTerminate方法

Handle Exceptions

处理异常

Exception handling mechanisms rely on the current call stack to perform any necessary clean up when an exception is thrown. Because each thread has its own call stack, each thread is therefore responsible for catching its own exceptions. Failing to catch an exception in a secondary thread is the same as failing to catch an exception in your main thread: the owning process is terminated. You cannot throw an uncaught exception to a different thread for processing

异常处理机制依赖当前调用堆栈来执行任何必要的清理,当抛出异常时。因为每个线程有它自己的调用堆栈,所以每个线程都负责捕捉自己的异常。没有在子线程中捕获异常与在主线程中无法捕获异常相同,所有的进程终止了。你不能把一个未捕获的异常抛到不同的线程进行处理.

If you need to notify another thread (such as the main thread) of an exceptional situation in the current thread, you should catch the exception and simply send a message to the other thread indicating what happened. Depending on your model and what you are trying to do, the thread that caught the exception can then continue processing (if that is possible), wait for instructions, or simply exit

如果你需要通知当前线程中异常情况的另一个线程(如主线程),则应该捕获异常,并且向另一个线程去发送一条消息,指示发生了什么。根据你的模型和你想做什么,捕获异常的线程可以继续处理(如果可能的话),等待指令或者退出.

In some cases, an exception handler may be created for you automatically. For example, the @synchronized directive in Objective-C contains an implicit exception handler

在某些情况下,可以自动为你创建一个异常处理程序,例如,oc中的@synchronized伪指令包含一个隐式异常处理程序。

Terminate Your Threads Cleanly

The best way for a thread to exit is naturally, by letting it reach the end of its main entry point routine. Although there are functions to terminate threads immediately, those functions should be used only as a last resort. Terminating a thread before it has reached its natural end point prevents the thread from cleaning up after itself. If the thread has allocated memory, opened a file, or acquired other types of resources, your code may be unable to reclaim those resources, resulting in memory leaks or other potential problems

线程退出的最佳办法是自然地通过让它到达其主入口的结尾。尽管有立刻终止线程的功能.但这些功能只能作为最后的手段使用。在线程达到其自然终点之前终止线程,可防治线程自身清除。如果线程分配了内存,打开一个文件或者获取了其他类型的资源,你的代码可能无法收回这些资源,导致内存泄漏或其他潜在问题.

Thread Safety in Libraries

库的线程安全

Although an application developer has control over whether an application executes with multiple threads, library developers do not. When developing libraries, you must assume that the calling application is multithreaded or could switch to being multithreaded at any time. As a result, you should always use locks for critical sections of code

虽然应用程序开发人员可以控制应用程序是否执行多个线程,但是库开发人员不会。当开发库时,你必须假设调用应用程序是多线程的,或者可以随时切换到多线程。因此你应该始终对关键代码段使用锁.

For library developers, it is unwise to create locks only when an application becomes multithreaded. If you need to lock your code at some point, create the lock object early in the use of your library, preferably in some sort of explicit call to initialize the library. Although you could also use a static library initialization function to create such locks, try to do so only when there is no other way. Execution of an initialization function adds to the time required to load your library and could adversely affect performance

对于库开发人员来说,仅当应用程序变为多线程时才创建锁是不明智的。如果你需要在某些时候锁定代码,请在使用库的早期创建锁对象,最好在某种显式调用中初始化库。虽然你也可以使用静态库初始化函数来创建这样的锁,但只有当没有其他的方式时才尝试这样做。初始化函数的执行增加了加载库所需的时间,并可能对性能产生不利影响.

Note: Always remember to balance calls to lock and unlock a mutex lock within your library. You should also remember to lock library data structures rather than rely on the calling code to provide a thread-safe environment

注意:始终记住平衡去调用锁和解锁库中的互斥锁.你还应该记住锁定库数据结构,而不是依靠调用代码来提供线程安全的环境.

If you are developing a Cocoa library, you can register as an observer for the NSWillBecomeMultiThreadedNotification if you want to be notified when the application becomes multithreaded. You should not rely on receiving this notification, though, as it might be dispatched before your library code is ever called

如果你正在开发Cocoa库,你可以注册NSWillBecomeMultiThreadedNotification的观察者,如果你希望在应用程序变为多线程时收到通知,你不应该依赖于接收此通知,因为它可能会在你的库代码被调用之前发送.

最后附上地址: 苹果文档地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容

  • PLEASE READ THE FOLLOWING APPLE DEVELOPER PROGRAM LICENSE...
    念念不忘的阅读 13,433评论 5 6
  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 9,382评论 0 23
  • 推荐给各位科研工作者一本好书:writing science。这本书不同于其他教写作的书,不是从写作的角度教你具体...
    石博士阅读 5,286评论 1 17
  • 第一题 神经系统科学家认为我们的大脑天生就带固定回路,只要对这种回路加以练习,就能决定我们所获得的能力,而并不是一...
    小莎妹儿阅读 178评论 0 0
  • 我想有必要记录下这一天。这几天身体上的异常让我的怀疑越来越重,公交车上每日晕车呕吐,内衣变小,容易饿爱吃肉,全身疲...
    家君在水之湄阅读 121评论 0 0